Serializowany obiekt Java do tablicy bajtów


292

Powiedzmy, że mam klasę możliwą do serializacji AppMessage.

Chciałbym przesłać go byte[]przez gniazda do innej maszyny, gdzie jest on przebudowywany z odebranych bajtów.

Jak mogłem to osiągnąć?


5
Dlaczego jak byte[]? Dlaczego po prostu nie napisać go bezpośrednio do gniazda ObjectOutputStreami czytać za pomocą ObjectInputStream?
Markiz Lorne

użyj wielbłąda Apache
ręka NOD

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

Odpowiedzi:


411

Przygotuj tablicę bajtów do wysłania:

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

Utwórz obiekt z tablicy bajtów:

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
Nie tak czytam pytanie. Dla mnie brzmi to tak, jakby jego problemem było to, jak przekonwertować obiekt na bajt [] - a nie jak go wysłać.
Taylor Leese

1
Taylor: tak, masz rację. Chcę zmienić obiekt w bajt [] i przesłać go. czy możesz również podać kod dotyczący tego, jak zmienić ten bajt [] w obiekt?
iTEgg

Zamknij zawsze strumień, aby zwolnić zasoby systemowe. (Edytowano w kodzie)
LuckyMalaka,

czy to może działać z obiektami, których nie mogę zaimplementować do serializacji?
KJW,

2
ObjectInput, ObjectOuput, ByteArrayOutputStreamI ByteArrayInputStreamwszystko zaimplementować AutoCloseableinterfejs, czy nie byłoby dobrą praktyką jest stosowanie go, aby uniknąć brakuje zamykając je przez pomyłkę? (Nie jestem do końca pewien, czy to jest najlepsza praktyka, dlatego zastanawiam.) Przykład: try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)){ /*Do stuff*/ }catch(IOException e){/*suppress exception*/}. Eliminuje to również potrzebę finalklauzuli i jej dodatkowych try-catch.
Ludvig Rydahl

307

Najlepszym sposobem na to jest użycie SerializationUtilsz Apache Commons Lang .

Aby serializować:

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

Aby dokonać deserializacji:

YourObject yourObject = SerializationUtils.deserialize(data)

Jak wspomniano, wymaga to biblioteki Commons Lang. Można go zaimportować za pomocą 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>

Plik jar

I więcej sposobów wymienionych tutaj

Alternatywnie można zaimportować całą kolekcję. Zobacz ten link


56
Dodano koszty ogólne? W tym momencie można również odbudować koło. Poważnie, o wiele łatwiej jest zrozumieć ten jeden wiersz i zmniejszyć możliwe błędy (takie jak nie zamykanie strumienia we właściwym czasie i tak dalej).
ALOToverflow 12.12.13

2
Najlepszy sposób, ponieważ korzystasz ze wspólnej biblioteki oferującej ci: 1) Wytrzymałość: ludzie korzystają z tego, a zatem jest zatwierdzony do pracy. 2) Robi powyższe (najpopularniejsza odpowiedź) z tylko 1 linią, dzięki czemu kod pozostaje czysty. 3) Ponieważ Dan tak powiedział. 4) Żartuję, jeśli chodzi o 3 :-)
Lawrence

2
Niestety metoda ogranicza rozmiar wyjściowy do 1024. Jeśli trzeba przekonwertować plik na strumień bajtów, lepiej go nie używać.
Abilash

Nie wolałbym tego do mikrousług. Biblioteka może sprawić, że będą większe niż w przypadku metod bezpośrednich.
Strefa

89

Jeśli używasz Java> = 7, możesz ulepszyć zaakceptowane rozwiązanie, używając try z zasobami :

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

I odwrotnie:

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

7

Można to zrobić za pomocą SerializationUtils , serializacji i deserializacji przez ApacheUtils w celu konwersji obiektu na bajt [] i odwrotnie, jak podano w odpowiedzi @uris.

Aby przekonwertować obiekt na bajt [] poprzez serializację:

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

Aby przekonwertować bajt [] na obiekt przez deserializację:

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

Kliknij link, aby pobrać org-apache-commons-lang.jar

Zintegruj plik .jar, klikając:

FileName -> Otwórz Ustawienia Medule -> Wybierz moduł -> Zależności -> Dodaj plik Jar i gotowe.

Mam nadzieję, że to pomaga .


3
nigdy nie dodawaj takiej zależności, użyj maven / gradle, aby pobrać zależność i dodaj ją do ścieżki kompilacji
Daniel Bo

4

Polecam również użyć narzędzia SerializationUtils. Chcę zarabiać na złym komentarzu @Abilash. SerializationUtils.serialize()Metoda jest nie ograniczony do 1024 bajtów, w przeciwieństwie do innej odpowiedzi tutaj.

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

Na pierwszy rzut oka możesz pomyśleć, że new ByteArrayOutputStream(1024)pozwoli to tylko na ustalony rozmiar. Ale jeśli przyjrzysz się uważnie ByteArrayOutputStream, zorientujesz się, że strumień wzrośnie, jeśli to konieczne:

Ta klasa implementuje strumień wyjściowy, w którym dane są zapisywane w tablicy bajtów. Bufor rośnie automatycznie, gdy dane są do niego zapisywane. Dane można odzyskać za pomocą toByteArray()i toString().


czy możesz dodać, jak zrobić odwrotnie? więc bajt [] do sprzeciwu? Wiem, że inni to mają, ale bardziej podoba mi się twoja odpowiedź i nie mogę uruchomić deserializacji. W każdym razie chcę uniknąć zwracania wartości null.
Tobias Kolb

1

Chciałbym przesłać jako bajt [] przez gniazda do innej maszyny

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

gdzie jest przebudowywany z odebranych bajtów.

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

1

Kolejna interesująca metoda pochodzi z com.fasterxml.jackson.databind.ObjectMapper

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

Zależność 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

Jeśli używasz sprężyny, dostępna jest klasa utylizacji w rdzeniu sprężynowym. Możesz po prostu zrobić

import org.springframework.util.SerializationUtils;

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

0

przykład kodu z 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

Jeśli chcesz miłego rozwiązania bez kopiowania i wklejania. Złap poniższy kod.

Przykład

MyObject myObject = ...

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

Źródło

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

To tylko zoptymalizowana forma kodu akceptowanej odpowiedzi na wypadek, gdyby ktoś chciał użyć jej w środowisku produkcyjnym:

    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 {

    }




}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.