Objeto serializable Java a matriz de bytes


292

Digamos que tengo una clase serializable AppMessage.

Me gustaría transmitirlo a byte[]través de sockets a otra máquina donde se reconstruye a partir de los bytes recibidos.

¿Cómo podría lograr esto?


55
¿Por qué como byte[]? ¿Por qué no escribirlo directamente en el zócalo ObjectOutputStreamy leerlo con ObjectInputStream?
Marqués de Lorne

use camello apache
la mano de NOD

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

Respuestas:


411

Prepare la matriz de bytes para enviar:

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
  }
}

Cree un objeto a partir de una matriz de bytes:

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
Así no es como leo la pregunta. Para mí, parece que su problema es cómo convertir el objeto en un byte [], no cómo enviarlo.
Taylor Leese

1
Taylor: sí, lo entendiste bien. Quiero convertir el objeto en un byte [] y transmitirlo. ¿puede proporcionar también el código sobre cómo convertir este byte [] en un objeto, por favor?
iTEgg

Cierre siempre cualquier secuencia para liberar los recursos del sistema. (Editado en código)
LuckyMalaka

¿Puede funcionar esto con objetos que no puedo implementar serializable?
KJW

2
ObjectInput, ObjectOuput, ByteArrayOutputStreamY ByteArrayInputStreamtoda implementar el AutoCloseableinterfaz, ¿no sería una buena práctica para usarlo para evitar perder su cierre por error? (No estoy del todo seguro de si esto es la mejor práctica, por eso me pregunto.) Ejemplo: try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)){ /*Do stuff*/ }catch(IOException e){/*suppress exception*/}. También elimina la necesidad de la finalcláusula y su adicional try-catch.
Ludvig Rydahl

307

La mejor manera de hacerlo es usarlo SerializationUtilsdesde Apache Commons Lang .

Para serializar:

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

Para deserializar:

YourObject yourObject = SerializationUtils.deserialize(data)

Como se mencionó, esto requiere la biblioteca Commons Lang. Se puede importar usando Gradle:

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

Maven

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

Archivo jar

Y más formas mencionadas aquí

Alternativamente, se puede importar toda la colección. Consulte este enlace


56
¿Sobrecarga adicional? También podría reconstruir la rueda en este punto. En serio, es mucho más fácil entender esta línea y reducir posibles errores (como no cerrar la transmisión en el momento adecuado y otras cosas).
ALOToverflow

2
La mejor manera porque utiliza una biblioteca común que le ofrece: 1) Robustez: la gente lo está utilizando y, por lo tanto, está validado para funcionar. 2) Hace lo anterior (la respuesta más popular) con solo 1 línea para que su código permanezca limpio. 3) Porque Dan lo dijo. 4) Solo estoy bromeando con respecto a 3 :-)
Lawrence

2
Desafortunadamente, el método restringe el tamaño de salida a 1024. Si uno necesita convertir un archivo a una secuencia de bytes, mejor no lo use.
Abilash

No preferiría este para microservicios. La biblioteca podría hacerlos más pesados ​​en tamaño que los métodos directos.
Zon

89

Si usa Java> = 7, podría mejorar la solución aceptada usando probar con recursos :

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

Y a la inversa:

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

7

Se puede hacer con SerializationUtils , con el método de serialización y deserialización de ApacheUtils para convertir el objeto en byte [] y viceversa, como se indica en la respuesta @uris.

Para convertir un objeto en byte [] serializando:

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

Para convertir el byte [] en objeto deserializando ::

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

Haga clic en el enlace para descargar org-apache-commons-lang.jar

Integre el archivo .jar haciendo clic en:

FileName -> Open Medule Settings -> Seleccione su módulo -> Dependencias -> Agregar archivo Jar y ya está.

Espero que esto ayude .


3
nunca agregue una dependencia como esta, use maven / gradle para descargar la dependencia y agréguela a la ruta de compilación
Daniel Bo

4

También recomiendo usar la herramienta SerializationUtils. Quiero ajustar un comentario equivocado de @Abilash. El SerializationUtils.serialize()método no está restringido a 1024 bytes, al contrario de otra respuesta aquí.

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 primera vista, puede pensar que new ByteArrayOutputStream(1024)solo permitirá un tamaño fijo. Pero si observa de cerca ByteArrayOutputStream, descubrirá que la corriente crecerá si es necesario:

Esta clase implementa una secuencia de salida en la que los datos se escriben en una matriz de bytes. El búfer crece automáticamente a medida que se escriben datos en él. Los datos se pueden recuperar con toByteArray()y toString().


¿Puedes agregar cómo hacer lo contrario? entonces byte [] para objetar? Sé que otros tienen esto, pero me gusta mucho su respuesta y no puedo lograr que la deserialización funcione. Quiero evitar volver nulo en cualquier caso.
Tobias Kolb

1

Me gustaría transmitirlo como byte [] sobre sockets a otra máquina

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

donde se reconstruye a partir de los bytes recibidos.

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

1

Otro método interesante es de com.fasterxml.jackson.databind.ObjectMapper

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

Dependencia de Maven

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

1

Spring Framework org.springframework.util.SerializationUtils

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

1

Si está utilizando spring, hay una clase de utilidad disponible en spring-core. Simplemente puedes hacer

import org.springframework.util.SerializationUtils;

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

0

ejemplo de código 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

En caso de que desee una buena solución de copiar y pegar sin dependencias. Toma el código a continuación.

Ejemplo

MyObject myObject = ...

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

Fuente

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

Esta es solo una forma de código optimizado de la respuesta aceptada en caso de que alguien quiera usar esto en producción:

    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 {

    }




}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.