2014-09-30 3 views
2

Я хочу разделить объекты Java в разных приложениях.de/serialize java-объекты в разных приложениях с использованием разных имен пакетов

Пока я использую те же названия пакетов в разных проектах, он отлично работает. Но если я меняю имена пакетов, это больше не работает.

Я попытался решить эту проблему, расширив класс ObjectInputStream и переопределив метод readClassDescriptor.

Но при этом я получаю следующее сообщение об ошибке:

java.io.StreamCorruptedException: invalid type code: 00 

... не знаю, как решить эту проблему.

Вот код, который я использую для расширенного класса ObjectInputStream:

public class MyObjectInputStream extends ObjectInputStream { 

    public static Map<String, Class> classNameMapping = initclassNameMapping(); 

    private static Map<String, Class> initclassNameMapping(){ 
     Map<String, Class> res = new HashMap<String, Class>(); 
     //ipxTest is the name of the package where the objects got serialized 
     res.put("ipxTest.IPX", interprojectxchangeTest.IPX.class); 
     res.put("ipxTest.A", interprojectxchangeTest.A.class); 
     return Collections.unmodifiableMap(res); 
    } 

    public MyObjectInputStream(InputStream in) throws IOException { 
     super(in); 
     enableResolveObject(true); 
    } 


    protected MyObjectInputStream() throws IOException, SecurityException { 
     super(); 
     enableResolveObject(true); 
    } 

    @Override 
    protected java.io.ObjectStreamClass readClassDescriptor() 
      throws IOException, ClassNotFoundException { 
     ObjectStreamClass desc = super.readClassDescriptor(); 
     if (classNameMapping.containsKey(desc.getName())) 
      return ObjectStreamClass.lookup(classNameMapping.get(desc.getName())); 
     return desc; 
    } 
} 

протокол IPX и А классы оба выглядят равными в различных проектах и ​​имеют каждый такую ​​же serialID.

+0

Эти вопросы могут быть полезны: http://stackoverflow.com/a/13262989/446554 и http://stackoverflow.com/a/13263036/446554 –

+0

Мой вопрос: почему переписывается «readClassDescriptor» метод не может решить описанную проблему. то есть, что исходный класс больше не доступен для jvm под его первоначальным именем ... – matthiasboesinger

ответ

4

Мое первое предложение - сделать вашу реализацию простой и прекратить борьбу с фреймворком - использовать те же имена пакетов для всех приложений. Я бы предложил сделать библиотеку из сериализуемых классов и поделиться ею между реализациями.

Если вы ДОЛЖНЫ сериализовать/десериализовать приложения с разными именами пакетов, то мое предложение состояло в том, чтобы отказаться от встроенной сериализации Java, которая тесно связана с именем класса и именем пакета, и использовать что-то вроде Gson для сериализации/десериализовать.

Gson позволяет указать TypeAdaper. Вы можете создавать и регистрировать TypeAdapter для каждого класса, который вы будете сериализовать/десериализовать, и указать имя класса (без имени пакета) как «тип» при сериализации, как в следующем примере, но использовать getSimpleName() вместо getCanonicalName ()

Когда десериализации, вы должны добавить правильное имя пакета в «тип»

вы должны были бы сделать TypeAdapters индивидуально для каждого приложения.

public class GsonTypeAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> { 
    @Override 
    public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { 
     JsonObject result = new JsonObject(); 
     result.add("type", new JsonPrimitive(src.getClass().getCanonicalName())); 
     result.add("properties", context.serialize(src, src.getClass())); 

     return result; 
    } 

    @Override 
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
     throws JsonParseException { 
     JsonObject jsonObject = json.getAsJsonObject(); 
     String type = jsonObject.get("type").getAsString(); 
     JsonElement element = jsonObject.get("properties"); 

     try { 
      return context.deserialize(element, Class.forName(type)); 
     } catch (ClassNotFoundException cnfe) { 
      throw new JsonParseException("Unknown element type: " + type, cnfe); 
     } 
    } 
} 
0

Название пакета класса является фундаментальной частью его полного имени.

Если matthiasboesinger - это имя ура, то matthias - это просто имя ура, чтобы идентифицировать вас, но часть босинга - это своего рода уникальный идентификатор имени.

Аналогично, в классах компилятор идентифицирует класс и их сериализованные объекты с их полным именем, а не только с первым именем.

в случае, если вы меняете имена пакетов, вы теряете целостность класса, так как разные классы могут существовать в разных пакетах с тем же именем.

поэтому, что вы пытаетесь, невозможно.

, если вы не напишете класс адаптера, который собирает данные из исходного класса с именем пакета и перекачивает данные в новый класс имени пакета.

но это только бьющееся вокруг куста.

+0

Мой вопрос: почему перезаписанный метод readClassDescriptor не может решить описанную проблему. то есть: что первоначальный класс больше не доступен для jvm под его первоначальным именем ... – matthiasboesinger