Reputation: 143
Let's say I have a domain object, Here is the pseudocode
public class SampleClass {
id
title
... a lot of other fields from database
public boolean equals(AnotherObj) {
return this.id.equals(AnotherObj.id);
}
}
The equals method is based on the id, which works for most scenarios. But in one scenario, the two objects shall be considered equal if the titles are the same. The objects are put in list and list.contains(obj) and list.indexOf(obj) is heavily invoked for business logic, which depends on the equals method.
How to override the equals method at runtime? The sampleClass object could contain complicated tree childrens and I don't want to copy it in the memory.
I want to create a wrapper for the existing object. The wrapper only contains the specific equals method, all other method call should still be passed to the existing object.
I looked into cglib but it has to generate the target object by itself, it cannot wrap an existing object.
Any easy way?
Upvotes: 0
Views: 1686
Reputation: 1074335
Rather than trying to wrap these objects, I would modify the class so that it understands what it should be checking (in each scenario) in its equals
method. Then in this particular situation, just set whatever state member (or whatever it is) that tells the object how equals
should work. Just be sure not to break the contract.
I would also recommend actually overriding Object#equals
(e.g., make sure your equals
accepts Object
, not just AnotherObj
). (And of course, as always, do hashCode
as well.)
But if you do want to do this, and you want to do it with equals
, it sounds like a job for the Facade pattern It's a bit of a pain in Java: You have to create another whole class that accepts the object as an argument in the constructor, implements all methods except equals
by just calling them on the object, and then (of course) implements equals
differently.
So basically:
class SampleSubclass extends SampleClass {
SampleClass inst;
SampleSubclass(SampleClass inst) {
this.inst = inst;
}
@override
String someMethod() {
return inst.someMethod();
}
// ...and so on...
@override
public boolean equals(AnotherObj other) { // <== But this really should accept Object, not AnotherObj
// ... implementation...
}
}
Upvotes: 1
Reputation: 121710
Assuming you are actually talking about Object
's .equals()
/.hashCode()
, which is not what your code currently does, you can do that using Guava's Equivalence
.
Create an equivalence:
public final class SampleClassIdEquivalence
extends Equivalence<SampleClass>
{
// override .doEquivalent(), .doHash()
}
Then you can use it like so:
final Equivalence<SampleClass> byId = new SampleClassIdEquivalence();
byId.equivalent(o1, o2);
Set<Equivalence.Wrapper<SampleClass>> set = ...
set.add(byId.wrap(whatever));
Then you can create other equivalences for equality by name or whatever; your choice.
In fact, Equivalence
is pretty much to .equals()
/.hashCode()
what Comparator
is to Comparable
.
Upvotes: 1