2

I need to figure out whenever two given interface implementation are the same. My naive approach was to test equality of their classes roughly by: first.getClass().equals(second.getClass()). It works until my code encountered (de)serialized lambda expressions. Which seem to change their Class instance during deserialization. Following example illustrates the case:

public interface SerializableSupplier<T> extends Serializable{
   T get();
}

private static final SerializableSupplier<Integer> FINAL_SUPPLIER = () -> 8;

public static void main(String args[]) throws IOException, ClassNotFoundException {


   ByteArrayOutputStream outStr = new ByteArrayOutputStream();
   ObjectOutputStream oss = new ObjectOutputStream(outStr);

   oss.writeObject(FINAL_SUPPLIER);
   oss.flush();
   oss.close();

   ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(outStr.toByteArray()));
   SerializableSupplier<Integer> supplierDeserialized = (SerializableSupplier<Integer>) ois.readObject();

   System.out.println(FINAL_SUPPLIER.getClass());
   System.out.println(supplierDeserialized.getClass());
   System.out.println(FINAL_SUPPLIER.getClass().equals(supplierDeserialized.getClass()));   
}

Which prints:

class cz.plastique.examples.LambdaChangingClass$$Lambda$1/295530567
class cz.plastique.examples.LambdaChangingClass$$Lambda$4/1854731462
false

The behavior is different when anonymous implementation is used:

private static final SerializableSupplier<Integer> ANONYMOUS_FINAL_SUPPLIER =
new SerializableSupplier<Integer>() {
   @Override
   public Integer get() {
     return 8;
   }
};

Which prints:

class cz.plastique.examples.LambdaChangingClass$1
class cz.plastique.examples.LambdaChangingClass$1
true

I'm puzzled by this. Why is the lambda changing it's class? And how else a'm able to recognized whenever two given interface implementations are the same even after serialization?

I suppose this has something to do with runtime lambda object construction. But I do not see how and why it is happening?

Full example code.

plastique
  • 1,164
  • 2
  • 9
  • 19
  • 2
    lambdas are generated at runtime, anonymous classes are not. Java doesn't make two lambdas which are basically the same use the same class. – Peter Lawrey Jul 04 '18 at 14:56
  • 1
    *"And how to recognize when two given interface implementations are the same even after serialization?"* After serialization, the interface implementations are different (classes being implementations), so the class test still works for that. Can you explain what you are actually trying to test? (Also, testing classes has never worked for testing whether two objects represent the same function, because of things like `Predicate p(boolean b) { return o -> b; }`.) – Radiodef Jul 04 '18 at 15:16
  • See also https://stackoverflow.com/questions/24095875/is-there-a-way-to-compare-lambdas – Radiodef Jul 04 '18 at 15:19
  • Hi @Radiodef, thanks for your interest. Point is that I need to do some init stuff which is expensive and part of it needs to be specified by user. So there is an interface user can implement and supply to do its initialization job. Initialized class is then cached. Cache is queried using instance of user interface. It works, but not when the instances are (de)serialized. – plastique Jul 04 '18 at 20:03

0 Answers0