ClassCastException: java.lang.Object cannot be cast to …

There can be two causes for this error message. First, maybe you really did cast an Object to something it’s not.

Older versions of EqualsVerifier

Second, it might be a generics problem. In this case, it will always be java.lang.Object that cannot be cast to some other class. This issue was solved in EqualsVerifier 2.0. If you haven’t upgraded yet, please do so if you can! If not, continue reading.

Consider the following (partial) class:

final class StringReference {
	private final AtomicReference<String> stringRef;

	@Override
	public boolean equals(Object obj) {
		referToGenericParameter();
		
		if (!(obj instanceof StringReference)) {
			return false;
		}
		StringReference other = (StringReference)obj;
		return stringRef.equals(other.stringRef);
	}

	private void referToGenericParameter() {
		stringRef.get().length();
	}
}

In this case, EqualsVerifier will say “java.lang.Object cannot be cast to java.lang.String”. EqualsVerifier can’t see that the AtomicReference’s generic type parameter is String (due to type erasure). Instead, it will just put in an Object. Normally, this isn’t a problem, but in this case, a direct reference is made to a String method in referToGenericParameter. Object doesn’t have a length() method, so the object inside the AtomicReference is (implicitly) cast to String. Since EqualsVerifier put in an Object, this fails.

How to fix this? It’s easy. Just add a call to withPrefabValues():

EqualsVerifier.forClass(StringReference.class)
    .withPrefabValues(AtomicReference.class,
        new AtomicReference<String>("string"),
        new AtomicReference<String>("another string"))
    .verify();

EqualsVerifier will always look inside the pool of prefabricated values before building its own. So in this case, when it looks for instances of AtomicReference, it will find two AtomicReferences with Strings already filled in. Problem solved!