title: Specify which fields are (not) serialized in ObjectOutputStream without using transient or serialPersistentFields
body: <p>Is there any way to tell an <code>ObjectOutputStream</code> which fields of a serializable class should be serialized without using the keyword <code>transient</code> and without defining an <code>serialPersistentFields</code>-array?</p>
  
  <hr>
  
  <p>Background: I need to use annotations to define which members of a class should be serialized (or better: not be serialized). The involved classes must implement the interface <code>Serializable</code>, but NOT <code>Externalizable</code>, so I don't want to implement the serialization/deserialization algorithm for each object but rather just use annotations for it. I can not use the <code>transient</code> keyword, because the annotation requires some further checks to determine whether a field should be serialized or not. These checks have to be done by the <code>ObjectOutputStream</code> (or in my own subclass of <code>ObjectOutputStream</code>).  I also cannot define a <code>serialPersistentFields</code>-array in each class, because as explained previously, at compilation time it is not defined which fields should be serialized.</p>
  
  <p>So the only thing that should be notet in the affected class is the annotation at field-level (<code>@Target(ElementType.FIELD)</code>).</p>
  
  <p>I've tried quite a lot of approaches in the last few days, but haven't found one which is working:</p>
  
  <hr>
  
  <p>The <code>ObjectOutputStream</code> has a method <code>writeObjectOverride(Object)</code> which can be used to define an own implementation of the serialization-process when extending <code>ObjectOutputStream</code>. This only works if the <code>ObjectOutputStream</code> is initialized with the no-argument-constructor because otherwise <code>writeObjectOverride</code> is never invoked. But this approach requires me to implement the whole serialization-process by myself and I don't want to do this, as it is quite complex and already implemented by the default <code>ObjectOutputStream</code>. I am looking for a way to just modify the default serialization implementation.</p>
  
  <hr>
  
  <p>Another approach was extending <code>ObjectOutputStream</code> again and overriding <code>writeObjectOverride(Object)</code> (after calling <code>enableReplaceObject(true)</code>). In this method, I tried using some kind of SerializationProxy (see <a href="https://stackoverflow.com/questions/702357/what-is-the-serialization-proxy-pattern">What is the Serialization Proxy Pattern?</a>) to encapsulate the serialized object in a proxy which defines a List of Fields which should be serialized. But this approach also fails as writeObjectOverride then is also called for the List of fields (<code>List&lt;SerializedField&gt; fields</code>) in the Proxy resulting in an infinite loop. </p>
  
  <p>Example:  </p>
  
  <pre><code>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&lt;?&gt; clazz;
          private List&lt;SerializedField&gt; fields = new LinkedList&lt;SerializedField&gt;();
  
          private SerializableProxy(Object obj) throws IllegalArgumentException,
                  IllegalAccessException {
              clazz = obj.getClass();
              for (Field field : getInheritedFields(obj.getClass())) {
                  // add all fields which don't have an DontSerialize-Annotation
                  if (!field.isAnnotationPresent(DontSerialize.class))
                      fields.add(new SerializedField(field.getType(), field
                              .get(obj)));
              }
          }
  
          public Object readResolve() {
              // TODO: reconstruct object of type clazz and set fields using
              // reflection
              return null;
          }
      }
  
      private class SerializedField {
          private Class&lt;?&gt; type;
          private Object value;
  
          public SerializedField(Class&lt;?&gt; type, Object value) {
              this.type = type;
              this.value = value;
          }
      }
  
      /** return all fields including superclass-fields */
      public static List&lt;Field&gt; getInheritedFields(Class&lt;?&gt; type) {
          List&lt;Field&gt; fields = new ArrayList&lt;Field&gt;();
          for (Class&lt;?&gt; c = type; c != null; c = c.getSuperclass()) {
              fields.addAll(Arrays.asList(c.getDeclaredFields()));
          }
          return fields;
      }
  
  }
  
  // I just use the annotation DontSerialize in this example for simlicity.
  // Later on I want to parametrize the annotation and do some further checks
  @Target(ElementType.FIELD)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface DontSerialize {
  }
  </code></pre>
  
  <hr>
  
  <p>When I found out that it is possible to modify modifiers at runtime (see <a href="https://stackoverflow.com/questions/3301635/change-private-static-final-field-using-java-reflection">Change private static final field using Java reflection</a>) I tried to set the transient-Modifier at runtime if the corresponding annotation was set.
  Unfortunately this also does not work, because the approach used in the previous link seems to work only on static fields.
  When trying it with non-static fields it runs without an exception but is not persisted because is looks like <code>Field.class.getDeclaredField(...)</code> returns new instances of the affected fields every time it is called:  </p>
  
  <pre><code>public void setTransientTest() throws SecurityException,
              NoSuchFieldException, IllegalArgumentException,
              IllegalAccessException {
          Class&lt;MyClass&gt; clazz = MyClass.class;
          // anyField is defined as "private String anyField"
          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");    
  }
  </code></pre>
  
  <p>The output is:  </p>
  
  <pre><code>1. is NOT transient
  2. is transient
  3. is NOT transient
  </code></pre>
  
  <p>So after calling getDeclaredField again (<code>Field field2 = clazz.getDeclaredField("anyField");</code>) it already lost the transient modifier.</p>
  
  <hr>
  
  <p>Next approach:<br>
  Extend <code>ObjectOutputStream</code> and override <code>ObjectOutputStream.PutField putFields()</code> and define an own PutField-implementation. PutField lets you specify which (additional) fields are serialized but unfortunately the interface only has a lot of methodes of the form <code>put(String name, &lt;type&gt; val)</code> and when implementing these I cannot associate the method calls with the class field it is invoked from. For instance when serializing a field declared as <code>private String test = "foo"</code> the method <code>put("test", "foo")</code> is invoked, but I cannot associate the value of <code>name</code> (which is <code>test</code>) with the class containing the field <code>test</code> because no reference to the containing class is available and therefore it is impossible to read the annotation noted for the field <code>test</code>.</p>
  
  <hr>
  
  <p>I also tried a few other approaches but as already mentioned I was not able to successfully serialize all fields except the ones with the annotation <code>DontSerialize</code> present.</p>
  
  <p>One thing I also came across were ByteCode manipulators. Maybe it is possible with these but I have a requirement for not using any external tools - it needs to be pure Java (1.5 or 1.6).</p>
  
  <hr>
  
  <p>Sorry for this really long post but I just wanted to show what I already tried and am hoping that someone can help me.
  Thanks in advance.</p>