web-dev-qa-db-fra.com

Comment sérialiser un objet dans une chaîne

Je suis en mesure de sérialiser un objet dans un fichier, puis de le restaurer à nouveau, comme indiqué dans l'extrait de code suivant. Je voudrais sérialiser l'objet dans une chaîne et stocker dans une base de données à la place. Quelqu'un peut-il m'aider?

LinkedList<Diff_match_patch.Patch> patches = // whatever...
FileOutputStream fileStream = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fileStream);
os.writeObject(patches1);
os.close();

FileInputStream fileInputStream = new FileInputStream("foo.ser");
ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
Object one = oInputStream.readObject();
LinkedList<Diff_match_patch.Patch> patches3 = (LinkedList<Diff_match_patch.Patch>) one;
os.close();
137
Sergio del Amo

Sergio:

Vous devriez utiliser BLOB . C'est assez simple avec JDBC. 

Le problème avec le deuxième code que vous avez posté est le codage. Vous devez en outre coder les octets pour vous assurer qu'aucun d'entre eux n'échoue.

Si vous voulez toujours l'écrire dans une chaîne, vous pouvez encoder les octets en utilisant Java.util.Base64

Vous devez néanmoins utiliser le type de données CLOB car vous ne savez pas combien de temps les données sérialisées vont durer.

Voici un exemple d'utilisation.

import Java.util.*;
import Java.io.*;

/** 
 * Usage sample serializing SomeClass instance 
 */
public class ToStringSample {

    public static void main( String [] args )  throws IOException,
                                                      ClassNotFoundException {
        String string = toString( new SomeClass() );
        System.out.println(" Encoded serialized version " );
        System.out.println( string );
        SomeClass some = ( SomeClass ) fromString( string );
        System.out.println( "\n\nReconstituted object");
        System.out.println( some );


    }

    /** Read the object from Base64 string. */
   private static Object fromString( String s ) throws IOException ,
                                                       ClassNotFoundException {
        byte [] data = Base64.getDecoder().decode( s );
        ObjectInputStream ois = new ObjectInputStream( 
                                        new ByteArrayInputStream(  data ) );
        Object o  = ois.readObject();
        ois.close();
        return o;
   }

    /** Write the object to a Base64 string. */
    private static String toString( Serializable o ) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream( baos );
        oos.writeObject( o );
        oos.close();
        return Base64.getEncoder().encodeToString(baos.toByteArray()); 
    }
}

/** Test subject. A very simple class. */ 
class SomeClass implements Serializable {

    private final static long serialVersionUID = 1; // See Nick's comment below

    int i    = Integer.MAX_VALUE;
    String s = "ABCDEFGHIJKLMNOP";
    Double d = new Double( -1.0 );
    public String toString(){
        return  "SomeClass instance says: Don't worry, " 
              + "I'm healthy. Look, my data is i = " + i  
              + ", s = " + s + ", d = " + d;
    }
}

Sortie: 

C:\samples>javac *.Java

C:\samples>Java ToStringSample
Encoded serialized version
rO0ABXNyAAlTb21lQ2xhc3MAAAAAAAAAAQIAA0kAAWlMAAFkdAASTGphdmEvbGFuZy9Eb3VibGU7T
AABc3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwf////3NyABBqYXZhLmxhbmcuRG91YmxlgLPCSilr+w
QCAAFEAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cL/wAAAAAAAAdAAQQUJ
DREVGR0hJSktMTU5PUA==


Reconstituted object
SomeClass instance says: Don't worry, I'm healthy. Look, my data is i = 2147483647, s = ABCDEFGHIJKLMNOP, d = -1.0

NOTE: pour Java 7 et les versions antérieures, vous pouvez voir l'original répondez ici

255
OscarRyz

Que diriez-vous d'écrire les données dans un ByteArrayOutputStream au lieu d'un FileOutputStream?

Sinon, vous pouvez sérialiser l'objet à l'aide de XMLEncoder, conserver le code XML, puis le désérialiser via XMLDecoder.

11
Outlaw Programmer

Merci pour d'excellentes réponses rapides. Je donnerai des votes immédiatement pour remercier votre aide. J'ai codé la meilleure solution à mon avis en fonction de vos réponses. 

LinkedList<Patch> patches1 = diff.patch_make(text2, text1);
try {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(bos);
    os.writeObject(patches1);
    String serialized_patches1 = bos.toString();
    os.close();


    ByteArrayInputStream bis = new ByteArrayInputStream(serialized_patches1.getBytes());
    ObjectInputStream oInputStream = new ObjectInputStream(bis);
    LinkedList<Patch> restored_patches1 = (LinkedList<Patch>) oInputStream.readObject();            



        // patches1 equals restored_patches1
    oInputStream.close();
} catch(Exception ex) {
    ex.printStackTrace();
}

Remarque i n'a pas envisagé d'utiliser JSON car il est moins efficace.

Remarque: Je prendrai en compte votre conseil de ne pas stocker un objet sérialisé sous forme de chaînes dans la base de données mais plutôt d'octet []. 

7
Sergio del Amo

Pourquoi ne pas persister l’objet sous forme de blob

4
Kristian

XStream fournit un utilitaire simple pour la sérialisation/désérialisation vers/à partir de XML, et c'est very quick. Stocker des CLOBs XML plutôt que des BLOBs binaires sera moins fragile, pour ne pas dire plus lisible.

4
skaffman

Si vous stockez un objet sous forme de données binaires dans la base de données, vous devez utiliser un type de données BLOB. La base de données est capable de la stocker plus efficacement et vous n'avez pas à vous soucier des encodages, etc. JDBC fournit des méthodes pour créer et récupérer des blobs en termes de flux. Si vous le pouvez, utilisez Java 6. Il a été possible d’apporter des améliorations à l’API JDBC qui facilitent beaucoup la gestion des blobs.

Si vous devez absolument stocker les données sous forme de chaîne, je vous recommande XStream pour le stockage basé sur XML (beaucoup plus simple que XMLEncoder), mais d'autres représentations d'objet peuvent s'avérer tout aussi utiles (par exemple, JSON). Votre approche dépend de la raison pour laquelle vous avez réellement besoin de stocker l'objet de cette manière.

3
Daniel Spiewak

Approche Java8, convertissant Object from/to String, inspirée de la réponse de OscarRyz . Pour le codage de /, Java.util.Base64 est requis et utilisé.

import Java.io.ByteArrayInputStream;
import Java.io.ByteArrayOutputStream;
import Java.io.IOException;
import Java.io.ObjectInputStream;
import Java.io.ObjectOutputStream;
import Java.io.Serializable;
import Java.util.Base64;
import Java.util.Optional;

interface ObjectHelper {

  static Optional<String> convertToString(final Serializable object) {
    try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(baos)) {
      oos.writeObject(object);
      return Optional.of(Base64.getEncoder().encodeToString(baos.toByteArray()));
    } catch (final IOException e) {
      e.printStackTrace();
      return Optional.empty();
    }
  }

  static <T extends Serializable> Optional<T> convertFrom(final String objectAsString) {
    final byte[] data = Base64.getDecoder().decode(objectAsString);
    try (final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
      return Optional.of((T) ois.readObject());
    } catch (final IOException | ClassNotFoundException e) {
      e.printStackTrace();
      return Optional.empty();
    }
  }
}
2
Markus Schulte

Examinez la classe Java.sql.PreparedStatement, en particulier la fonction

http://Java.Sun.com/javase/6/docs/api/Java/sql/PreparedStatement.html#setBinaryStream(int,%20Java.io.InputStream)

Ensuite, jetez un coup d’œil à la classe Java.sql.ResultSet, plus précisément à la fonction

http://Java.Sun.com/javase/6/docs/api/Java/sql/ResultSet.html#getBinaryStream(int)

Gardez à l'esprit que si vous sérialisez un objet dans une base de données et que vous modifiez ensuite l'objet dans votre code dans une nouvelle version, le processus de désérialisation peut facilement échouer car la signature de votre objet a été modifiée. Une fois, j’ai commis cette erreur en enregistrant des préférences personnalisées sérialisées, puis en modifiant la définition des préférences. Soudain, je ne pouvais plus lire aucune des informations précédemment numérotées.

Vous feriez peut-être mieux d'écrire des colonnes encombrantes par propriété dans une table et de composer et décomposer l'objet de cette manière, afin d'éviter ce problème avec les versions d'objet et la désérialisation. Ou encore, écrivez les propriétés dans une table de hachage, comme un objet Java.util.Properties, puis sérialisez l'objet de propriétés qui est extrêmement peu susceptible de changer.

1
Josh

Le flux sérialisé est juste une séquence d'octets (octets). La question est donc de savoir comment convertir une séquence d'octets en chaîne, et inversement. De plus, il doit utiliser un ensemble limité de codes de caractères s'il doit être stocké dans une base de données.

La solution évidente au problème consiste à modifier le champ en LOB binaire. Si vous souhaitez vous en tenir à un caractère générique LOB, vous devez alors coder selon un schéma tel que base64, hex ou uu.

1

Vous pouvez utiliser les classes de construction Sun.misc.Base64Decoder et Sun.misc.Base64Encoder pour convertir les données binaires de la sérialisation en chaîne. Vous n’avez pas besoin de classes supplémentaires car elles sont intégrées.

1
Saboteur

vous pouvez utiliser UUEncoding

0
CiNN

Solution simple, a travaillé pour moi

public static byte[] serialize(Object obj) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(out);
    os.writeObject(obj);
    return out.toByteArray();
}
0
priyanka_rao