Is it possible to indicate ObjectOutputStreamwhich fields of the serializable class should be serialized without using the keyword transientand without defining serialPersistentFields-array?
Reference Information. I need to use annotations to determine which members of the class should be serialized (or better: not to be serialized). The classes involved must implement the interface Serializable, but NOT Externalizable, so I do not want to implement a serialization / deserialization algorithm for each object, but just use annotations for it. I cannot use the keyword transientbecause annotation requires some additional checks to determine if the field should be serialized or not. These checks should be done with ObjectOutputStream(or in my own subclass ObjectOutputStream). I also can not define a serialPersistentFields-array in each class, because, as explained earlier, at compile time it is not determined which fields should be serialized.
So, the only thing that should be notes in the affected class is the annotation at the field level ( @Target(ElementType.FIELD)).
In the past few days, I have tried many approaches, but have not found what works:
ObjectOutputStreamhas a method writeObjectOverride(Object)that can be used to determine your own implementation of the serialization process during expansion ObjectOutputStream. This only works if it is ObjectOutputStreaminitialized by the no-argument-constructor because it is writeObjectOverridenever called otherwise . But this approach requires that I myself implement the entire serialization process, and I do not want to do this, because it is quite complex and already implemented by default ObjectOutputStream. I am looking for a way to just change the default serialization implementation.
ObjectOutputStream writeObjectOverride(Object) ( enableReplaceObject(true)). - SerializationProxy (. - Serialization?), -, , . , writeObjectOverride (List<SerializedField> fields) , .
:
public class AnnotationAwareObjectOutputStream extends ObjectOutputStream {
public AnnotationAwareObjectOutputStream(OutputStream out)
throws IOException {
super(out);
enableReplaceObject(true);
}
@Override
protected Object replaceObject(Object obj) throws IOException {
try {
return new SerializableProxy(obj);
} catch (Exception e) {
return new IOException(e);
}
}
private class SerializableProxy implements Serializable {
private Class<?> clazz;
private List<SerializedField> fields = new LinkedList<SerializedField>();
private SerializableProxy(Object obj) throws IllegalArgumentException,
IllegalAccessException {
clazz = obj.getClass();
for (Field field : getInheritedFields(obj.getClass())) {
if (!field.isAnnotationPresent(DontSerialize.class))
fields.add(new SerializedField(field.getType(), field
.get(obj)));
}
}
public Object readResolve() {
return null;
}
}
private class SerializedField {
private Class<?> type;
private Object value;
public SerializedField(Class<?> type, Object value) {
this.type = type;
this.value = value;
}
}
public static List<Field> getInheritedFields(Class<?> type) {
List<Field> fields = new ArrayList<Field>();
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DontSerialize {
}
, (. Java) .
, , , , , .
, , Field.class.getDeclaredField(...) , :
public void setTransientTest() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Class<MyClass> clazz = MyClass.class;
Field field = clazz.getDeclaredField("anyField");
System.out.println("1. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field modifiersField = Field.class.getDeclaredField("modifiers");
boolean wasAccessible = modifiersField.isAccessible();
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() | Modifier.TRANSIENT);
modifiersField.setAccessible(wasAccessible);
System.out.println("2. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field field2 = clazz.getDeclaredField("anyField");
System.out.println("3. is "
+ (Modifier.isTransient(field2.getModifiers()) ? "" : "NOT ")
+ "transient");
}
:
1. is NOT transient
2. is transient
3. is NOT transient
, getDeclaredField (Field field2 = clazz.getDeclaredField("anyField");) .
:
ObjectOutputStream ObjectOutputStream.PutField putFields() PutField. PutField , () , , , put(String name, <type> val), , . , , private String test = "foo", put("test", "foo"), name ( test) , test, , test.
, , , , , DontSerialize.
, , - ByteCode. , , - - Java (1.5 1.6).
, , , , - .
.