Сериализуемый Java-объект в массив байтов


292

Допустим, у меня есть сериализуемый класс AppMessage.

Я хотел бы передать его как byte[]через сокеты на другую машину, где он восстанавливается из полученных байтов.

Как я мог достичь этого?


5
Почему как byte[]? Почему бы просто не записать это прямо в сокет ObjectOutputStreamи не прочитать ObjectInputStream?
маркиз Лорн

использовать Apache верблюд
рука NOD

1
new ObjectMapper().writeValueAsBytes(JAVA_OBJECT_HERE)
Асад

Ответы:


411

Подготовьте байтовый массив для отправки:

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

Создайте объект из байтового массива:

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
Я так не читаю вопрос. Для меня это звучит так, как будто его проблема в том, как преобразовать объект в байт [], а не в том, как его отправить.
Тейлор Лиз

1
Тейлор: да, вы правильно поняли. я хочу превратить объект в байт [] и передать его. не могли бы вы также предоставить код относительно того, как превратить этот байт [] в объект, пожалуйста?
iTEgg

Пожалуйста, всегда закрывайте любой поток, чтобы освободить системные ресурсы. (Отредактировано в коде)
LuckyMalaka

это может работать с объектами, которые я не могу реализовать сериализуемым?
KJW

2
ObjectInput, ObjectOuput, ByteArrayOutputStreamИ ByteArrayInputStreamвсе реализовать AutoCloseableинтерфейс, не будет ли хорошая практика , чтобы использовать его , чтобы не пропустить их закрытия по ошибке? (Я не совсем уверен, что это лучшая практика, поэтому я интересно.) Пример: try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)){ /*Do stuff*/ }catch(IOException e){/*suppress exception*/}. Это также устраняет необходимость в finalпункте и его дополнительном try-catch.
Людвиг Райдал

307

Лучший способ сделать это - использовать SerializationUtilsApache Commons Lang .

Для сериализации:

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

Для десериализации:

YourObject yourObject = SerializationUtils.deserialize(data)

Как уже упоминалось, для этого требуется библиотека Commons Lang. Его можно импортировать с помощью 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>

Jar файл

И другие способы, упомянутые здесь

Кроме того, вся коллекция может быть импортирована. См этой ссылки


56
Добавлены накладные расходы? Можно также восстановить колесо на этом этапе. Серьезно, гораздо проще понять эту однострочность и уменьшить возможные ошибки (например, не закрывать поток в нужное время и еще много чего).
ALOToverflow

2
Лучший способ, потому что вы используете общую библиотеку, которая предлагает вам: 1) Надежность: люди используют это, и, таким образом, оно работает. 2) Это делает выше (самый популярный ответ) только с 1 строкой, поэтому ваш код остается чистым. 3) Потому что Дэн так сказал. 4) Я просто шучу по поводу 3 :-)
Лоуренс

2
К сожалению, метод ограничивает размер вывода до 1024. Если нужно преобразовать файл в поток байтов, лучше не использовать это.
Абилаш

Я бы не предпочел этот для микросервисов. Библиотека может сделать их тяжелее по размеру, чем прямые методы.
Зон

89

Если вы используете Java> = 7, вы можете улучшить принятое решение, используя try с ресурсами :

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

И наоборот:

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

7

Это можно сделать с помощью SerializationUtils , с помощью метода сериализации и десериализации ApacheUtils для преобразования объекта в byte [] и наоборот, как указано в ответе @uris.

Чтобы преобразовать объект в byte [] путем сериализации:

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

Чтобы преобразовать byte [] в объект путем десериализации ::

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

Нажмите на ссылку, чтобы загрузить org-apache-commons-lang.jar

Интегрируйте файл .jar, нажав:

FileName -> Открыть настройки Medule -> Выберите свой модуль -> Зависимости -> Добавить файл Jar, и все готово.

Надеюсь, это поможет .


3
никогда не добавляйте такую ​​зависимость, используйте maven / gradle для загрузки зависимости и добавьте ее в путь сборки
Daniel Bo

4

Я также рекомендую использовать инструмент SerializationUtils. Я хочу исправить неправильный комментарий @Abilash. SerializationUtils.serialize()Метод не ограничивается до 1024 байт, что противоречит другой ответ здесь.

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();
}

С первого взгляда , вы можете подумать, что new ByteArrayOutputStream(1024)разрешите только фиксированный размер. Но если вы внимательно посмотрите на ByteArrayOutputStream, вы поймете, что поток будет расти, если это необходимо:

Этот класс реализует выходной поток, в котором данные записываются в байтовый массив. Буфер автоматически увеличивается при записи данных в него. Данные могут быть получены с помощью toByteArray()и toString().


можешь добавить как сделать наоборот? так byte [] возразить? Я знаю, что у других есть это, но мне нравится ваш ответ намного больше, и я не могу заставить десериализацию работать. Я хочу, чтобы избежать возврата нуля в любом случае.
Тобиас Колб

1

Я хотел бы передать его в виде байта [] через сокеты на другую машину

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

где это восстановлено от полученных байтов.

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

1

Еще один интересный метод из com.fasterxml.jackson.databind.ObjectMapper

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

Maven Dependency

<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

Если вы используете Spring, в Spring-Core доступен класс утилит. Вы можете просто сделать

import org.springframework.util.SerializationUtils;

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

0

Пример кода с 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

В случае, если вы хотите хорошее решение для копирования и вставки зависимостей. Возьмите код ниже.

пример

MyObject myObject = ...

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

Источник

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

Это просто оптимизированная кодовая форма принятого ответа на случай, если кто-то захочет использовать это в работе:

    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 {

    }




}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.