Matrice da oggetto serializzabile Java a byte


292

Diciamo che ho una classe serializzabile AppMessage.

Vorrei trasmetterlo come byte[]socket su un'altra macchina dove viene ricostruito dai byte ricevuti.

Come ho potuto raggiungere questo obiettivo?


5
Perché come byte[]? Perché non scriverlo direttamente nel socket con ObjectOutputStreame leggerlo con ObjectInputStream?
Marchese di Lorne,

usa apache camel
la mano di NOD il

1
new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)
Asad Shakeel,

Risposte:


411

Preparare l'array di byte per l'invio:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
  out = new ObjectOutputStream(bos);   
  out.writeObject(yourObject);
  out.flush();
  byte[] yourBytes = bos.toByteArray();
  ...
} finally {
  try {
    bos.close();
  } catch (IOException ex) {
    // ignore close exception
  }
}

Crea un oggetto da un array di byte:

ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
ObjectInput in = null;
try {
  in = new ObjectInputStream(bis);
  Object o = in.readObject(); 
  ...
} finally {
  try {
    if (in != null) {
      in.close();
    }
  } catch (IOException ex) {
    // ignore close exception
  }
}

48
Non è così che ho letto la domanda. Per me sembra che il suo problema sia come convertire l'oggetto in un byte [] - non come inviarlo.
Taylor Leese,

1
Taylor: sì hai capito bene. voglio trasformare l'oggetto in un byte [] e trasmetterlo. puoi fornire anche il codice su come trasformare questo byte [] in un oggetto, per favore?
iTEgg,

Chiudi sempre qualsiasi flusso per liberare le risorse di sistema. (Modificato nel codice)
LuckyMalaka

può funzionare con oggetti che non posso implementare serializzabili?
KJW,

2
ObjectInput, ObjectOuput, ByteArrayOutputStreamE ByteArrayInputStreamtutto implementare l' AutoCloseableinterfaccia, Non sarebbe buona pratica da usare per evitare di perdere loro chiusura per errore? (Io non sono del tutto sicuro se questa è la migliore pratica, è per questo che mi chiedo.) Esempio: try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)){ /*Do stuff*/ }catch(IOException e){/*suppress exception*/}. Elimina inoltre la necessità della finalclausola e del suo supplemento try-catch.
Ludvig Rydahl,

307

Il modo migliore per farlo è usare SerializationUtilsda Apache Commons Lang .

Per serializzare:

byte[] data = SerializationUtils.serialize(yourObject);

Per deserializzare:

YourObject yourObject = SerializationUtils.deserialize(data)

Come accennato, ciò richiede la libreria Commons Lang. Può essere importato usando Gradle:

compile 'org.apache.commons:commons-lang3:3.5'

Esperto di:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.5</version>
</dependency>

File Jar

E altri modi menzionati qui

In alternativa, è possibile importare l'intera raccolta. Fai riferimento a questo link


56
Aggiunto sovraccarico? Potrebbe anche ricostruire la ruota a questo punto. Scherzi a parte, è molto più facile capire questo one-liner e ridurre possibili errori (come non chiudere lo stream al momento giusto e quant'altro).
ALOToverflow

2
Il modo migliore perché usi una libreria comune che ti offre: 1) Robustezza: le persone lo usano e quindi è validato per funzionare. 2) Fa quanto sopra (risposta più popolare) con solo 1 riga in modo che il codice rimanga pulito. 3) Perché Dan l'ha detto. 4) Sto solo scherzando riguardo a 3 :-)
Lawrence il

2
Sfortunatamente, il metodo limita la dimensione dell'output a 1024. Se è necessario convertire un file in un flusso di byte, è meglio non utilizzarlo.
Abilash,

Non preferirei questo per i microservizi. La libreria potrebbe renderli più pesanti delle dimensioni, rispetto ai metodi diretti.
Zon,

89

Se si utilizza Java> = 7, è possibile migliorare la soluzione accettata utilizzando provare con le risorse :

private byte[] convertToBytes(Object object) throws IOException {
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutput out = new ObjectOutputStream(bos)) {
        out.writeObject(object);
        return bos.toByteArray();
    } 
}

E viceversa:

private Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException {
    try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
         ObjectInput in = new ObjectInputStream(bis)) {
        return in.readObject();
    } 
}

7

Può essere fatto da SerializationUtils , serializzando e deserializzando il metodo da ApacheUtils per convertire l'oggetto in byte [] e viceversa, come indicato nella risposta @uris.

Per convertire un oggetto in byte [] serializzando:

byte[] data = SerializationUtils.serialize(object);

Per convertire byte [] in oggetto deserializzando ::

Object object = (Object) SerializationUtils.deserialize(byte[] data)

Fare clic sul collegamento per scaricare org-apache-commons-lang.jar

Integrare il file .jar facendo clic su:

FileName -> Apri impostazioni medule -> Seleziona il tuo modulo -> Dipendenze -> Aggiungi file Jar e il gioco è fatto.

Spero che questo aiuti .


3
non aggiungere mai una dipendenza come questa, usare maven / gradle per scaricare la dipendenza e aggiungerla al percorso di compilazione
Daniel Bo

4

Consiglio anche di usare lo strumento SerializationUtils. Voglio fare un commento su un commento sbagliato di @Abilash. Il SerializationUtils.serialize()metodo non è limitato a 1024 byte, contrariamente a un'altra risposta qui.

public static byte[] serialize(Object object) {
    if (object == null) {
        return null;
    }
    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
    try {
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        oos.flush();
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
    }
    return baos.toByteArray();
}

A prima vista may potresti pensare che new ByteArrayOutputStream(1024)consentirà solo una dimensione fissa. Ma se dai un'occhiata da vicino a ByteArrayOutputStream, scoprirai che il flusso crescerà se necessario:

Questa classe implementa un flusso di output in cui i dati vengono scritti in una matrice di byte. Il buffer cresce automaticamente man mano che i dati vengono scritti su di esso. I dati possono essere recuperati utilizzando toByteArray()e toString().


puoi aggiungere come fare il contrario? quindi byte [] per obiettare? So che gli altri hanno questo, ma mi piace molto la tua risposta e non riesco a far funzionare la deserializzazione. Voglio evitare di restituire null in ogni caso.
Tobias Kolb,

1

Vorrei trasmetterlo come byte [] su socket a un'altra macchina

// When you connect
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
// When you want to send it
oos.writeObject(appMessage);

dove viene ricostruito dai byte ricevuti.

// When you connect
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
// When you want to receive it
AppMessage appMessage = (AppMessage)ois.readObject();

1

Un altro metodo interessante viene da com.fasterxml.jackson.databind.ObjectMapper

byte[] data = new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)

Dipendenza di Maven

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

1

Quadro di primavera org.springframework.util.SerializationUtils

byte[] data = SerializationUtils.serialize(obj);

1

Se stai usando spring, c'è una classe util disponibile in spring-core. Puoi semplicemente farlo

import org.springframework.util.SerializationUtils;

byte[] bytes = SerializationUtils.serialize(anyObject);
Object object = SerializationUtils.deserialize(bytes);

0

esempio di codice con java 8+:

public class Person implements Serializable {

private String lastName;
private String firstName;

public Person() {
}

public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getFirstName() {
    return firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

@Override
public String toString() {
    return "firstName: " + firstName + ", lastName: " + lastName;
}
}


public interface PersonMarshaller {
default Person fromStream(InputStream inputStream) {
    try (ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
        Person person= (Person) objectInputStream.readObject();
        return person;
    } catch (IOException | ClassNotFoundException e) {
        System.err.println(e.getMessage());
        return null;
    }
}

default OutputStream toStream(Person person) {
    try (OutputStream outputStream = new ByteArrayOutputStream()) {
        ObjectOutput objectOutput = new ObjectOutputStream(outputStream);
        objectOutput.writeObject(person);
        objectOutput.flush();
        return outputStream;
    } catch (IOException e) {
        System.err.println(e.getMessage());
        return null;
    }

}

}

0

Nel caso in cui desideri una bella soluzione copia-incolla senza dipendenze. Prendi il codice qui sotto.

Esempio

MyObject myObject = ...

byte[] bytes = SerializeUtils.serialize(myObject);
myObject = SerializeUtils.deserialize(bytes);

fonte

import java.io.*;

public class SerializeUtils {

    public static byte[] serialize(Serializable value) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try(ObjectOutputStream outputStream = new ObjectOutputStream(out)) {
            outputStream.writeObject(value);
        }

        return out.toByteArray();
    }

    public static <T extends Serializable> T deserialize(byte[] data) throws IOException, ClassNotFoundException {
        try(ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
            //noinspection unchecked
            return (T) new ObjectInputStream(bis).readObject();
        }
    }
}

0

Questa è solo una forma di codice ottimizzata della risposta accettata nel caso qualcuno voglia utilizzarla in produzione:

    public static void byteArrayOps() throws IOException, ClassNotFoundException{

    String str="123";
     byte[] yourBytes = null;

    // Convert to byte[]

    try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out =  new ObjectOutputStream(bos);) {


      out.writeObject(str);
      out.flush();
      yourBytes = bos.toByteArray();

    } finally {

    }

    // convert back to Object

    try(ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
            ObjectInput in = new ObjectInputStream(bis);) {

      Object o = in.readObject(); 

    } finally {

    }




}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.