I am operating under the assumption that you have a .class file for Person, but no .class file for Address. (Perhaps Person is a dependency from a different project?)
The reason you cannot serialize Person (even though the Address field is transient) is that the serialization API uses the Java reflection API. Although the JVM will load a class without loading all of its dependencies, the reflection API is not as forgiving.
The first time the reflection API is used to retrieve field information for a particular class, it retrieves and caches information for all fields in the class. To do this, it has to resolve the types for every field in the class, and thus will attempt to load the class files for every field. (You can see this in the Java source code: ObjectOutputStream uses ObjectStreamClass, which calls Class.getDeclaredField, which calls a private method privateGetDeclaredFields, which resolves and caches all the field definitions for the class.)
As a workaround, if your code never actually uses any objects of type Address, you can simply create an empty Address class in the correct package, compile it, and add it to your class path:
public class Address { }
For those who think it isn't possible to use Person at runtime without an Address class definition, the following three classes demonstrate what the OP is talking about:
Person.java
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private transient Address address;
public Person(String name) { this.name = name; }
public Address getAddress() { return address; }
public String getName() { return name; }
}
Address.java
public class Address {
private String address;
public String getAddress() { return address; }
}
Test.java
import java.io.FileOutputStream;
import java.io.ObjectOuputStream;
public class Test {
public static void main(String...args) throws Exception {
Person person = new Person("John Doe");
System.out.println("Person successfully instantiated with name " + person.getName());
// now attempt to serialize
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.out"));
out.writeObject(person); // NoClassDefFoundError thrown here if Address.class doesn't exist
out.close();
}
}
Now compile Test.java, delete Address.class, and run Test:
$ javac Test.java
$ rm Address.class
$ java Test
Person successfully instantiated with name John Doe
Exception in thread "main" java.lang.NoClassDefFoundError: LAddress;
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2308)
at java.lang.Class.getDeclaredField(Class.java:1897)
at java.io.ObjectStreamClass.getDeclaredSUID(ObjectStreamClass.java:1624)
at java.io.ObjectStreamClass.access$700(ObjectStreamClass.java:69)
at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:442)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:430)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:327)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1130)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at Test.main(Test.java:10)
Caused by: java.lang.ClassNotFoundException: Address
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
... 12 more