Related
A few weeks back I wrote a Java class with the following behavior:
Each object contains a single final integer field
The class contains a static Map (Key: Integer, Content: MyClass)
Whenever an object of the class is instantiated a look-up is done, if an object with the wanted integer field already exists in the static map: return it, otherwise create one and put it in the map.
As code:
public class MyClass
{
private static Map<Integer, MyClass> map;
private final int field;
static
{
map = new HashMap<>();
}
private MyClass(int field)
{
this.field = field;
}
public static MyClass get(int field)
{
synchronized (map)
{
return map.computeIfAbsent(field, MyClass::new);
}
}
}
This way I can be sure, that only one object exists for each integer (as field). I'm currently concerned, that this will prevent the GC to collect objects, which I no longer need, since the objects are always stored in the map (a reference exists)...
If I wrote a loop like function like this:
public void myFunction() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
MyClass c = MyClass.get(i);
// DO STUFF
}
}
I would end up with Integer.MAX_VALUE objects in memory after calling the method. Is there a way I can check, whether references to objects in the map exists and otherwise remove them?
This looks like a typical case of the multiton pattern: You want to have at most one instance of MyClass for a given key. However, you also seem to want to limit the amount of instances created. This is very easy to do by lazily instantiating your MyClass instances as you need them. Additionally, you want to clean up unused instances:
Is there a way I can check, whether references to objects in the map exists and otherwise remove them?
This is exactly what the JVM's garbage collector is for; There is no reason to try to implement your own form of "garbage collection" when the Java core library already provides tools for marking certain references as "not strong", i.e. should refer to a given object only if there is a strong reference (i.e. in Java, a "normal" reference) somewhere referring to it.
Implementation using Reference objects
Instead of a Map<Integer, MyClass>, you should use a Map<Integer, WeakReference<MyClass>> or a Map<Integer, SoftReference<MyClass>>: Both WeakReference and SoftReference allow the MyClass instances they refer to to be garbage-collected if there are no strong (read: "normal") references to the object. The difference between the two is that the former releases the reference on the next garbage collection action after all strong references are gone, while the latter one only releases the reference when it "has to", i.e. at some point which is convenient for the JVM (see related SO question).
Plus, there is no need to synchronize your entire Map: You can simply use a ConcurrentHashMap (which implements ConcurrentMap), which handles multi-threading in a way much better than by locking all access to the entire map. Therefore, your MyClass.get(int) could look like this:
private static final ConcurrentMap<Integer, Reference<MyClass>> INSTANCES = new ConcurrentHashMap<>();
public static MyClass get(final int field) {
// ConcurrentHashMap.compute(...) is atomic <https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction->
final Reference<MyClass> ref = INSTANCES.compute(field, (key, oldValue) -> {
final Reference<MyClass> newValue;
if (oldValue == null) {
// No instance has yet been created; Create one
newValue = new SoftReference<>(new MyClass(key));
} else if (oldValue.get() == null) {
// The old instance has already been deleted; Replace it with a
// new reference to a new instance
newValue = new SoftReference<>(new MyClass(key));
} else {
// The existing instance has not yet been deleted; Re-use it
newValue = oldValue;
}
return newValue;
});
return ref.get();
}
Finally, in a comment above, you mentioned that you would "prefer to cache maybe up to say 1000 objects and after that only cache, what is currently required/referenced". Although I personally see little (good) reason for it, it is possible to perform eager instantiation on the "first"† 1000 objects by adding them to the INSTANCES map on creation:
private static final ConcurrentMap<Integer, Reference<MyClass>> INSTANCES = createInstanceMap();
private static ConcurrentMap<Integer, Reference<MyClass>> createInstanceMap() {
// The set of keys to eagerly initialize instances for
final Stream<Integer> keys = IntStream.range(0, 1000).boxed();
final Collector<Integer, ?, ConcurrentMap<Integer, Reference<MyClass>>> mapFactory = Collectors
.toConcurrentMap(Function.identity(), key -> new SoftReference<>(new MyClass(key)));
return keys.collect(mapFactory);
}
†How you define which objects are the "first" ones is up to you; Here, I'm just using the natural order of the integer keys because it's suitable for a simple example.
Your function for examining your cache is cringe worthy. First, as you said, it creates all the cache objects. Second, it iterates Integer.MAX_VALUE times.
Better would be:
public void myFunction() {
for(MyClass c : map.values()) {
// DO STUFF
}
}
To the issue at hand: Is it possible to find out whether an Object has references to it?
Yes. It is possible. But you won't like it.
http://docs.oracle.com/javase/1.5.0/docs/guide/jvmti/jvmti.html
jvmtiError
IterateOverReachableObjects(jvmtiEnv* env,
jvmtiHeapRootCallback heap_root_callback,
jvmtiStackReferenceCallback stack_ref_callback,
jvmtiObjectReferenceCallback object_ref_callback,
void* user_data)
Loop over all reachable objects in the heap. If a MyClass object is reachable, then, well, it is reachable.
Of course, by storing the object in your cache, you are making it reachable, so you'd have to change your cache to WeakReferences, and see if you can exclude those from the iteration.
And you're no longer using pure Java, and jvmti may not be supported by all VM's.
As I said, you won't like it.
I have multidimensional double[][] arrays of which each element has a set of properties.
I designed these properties as a Class:
public class ElemProperties
{
public double prop1;
...
}
Linking them with the elements of the array using a HashMap:
HashMap<double[][], ElemProperties> elemProperties;
using it like e.g:
elemProperties.get(exampleArray).getProp1();
However, this only serves as a mapping between the whole array and properties. What I'm trying to do is to actually map the elements. Since Java doesn't have pointers, I'm kind of stuck at this position. This design seems very convoluted is there a better way to achieve this goal?
First attempt would be:
public class Elem {
private double value;
private double additionalProperty1;
private double additionalProperty2;
...
}
And create an Elem[][] instead of a double[][].
This at least works but multi-dimensional arrays aren't too efficient and aren't too expressive either, so the next question is whether you could group them using a different structure.
If the additional properties are optional or could be shared between multiple elements, you would need to write objects for them too, but the starting point is the same.
It is of course possible that you genuinely need a Map to link values to additional properties "because of reasons". In that case you can do something like this:
public class Container {
private double[][] values;
private Map<Double,AdditionalProperties> properties;
public double getValue(int x, int y) {
return values[x][y];
}
public AdditionalProperties getProperties(int x, int y) {
return properties.get( getValue(x, y ) );
}
}
This way you can hide the fact that you use two separate data structures to store the data, and maintain data integrity between them.
Note though that this is semantically very different from the first solution. In particular, positions containing the same value will share their AdditionalProperties.
(There are also practical problems with this implementation, #dasblinkenlight already pointed out why using doubles as keys to a map is an issue, the other is that an autoboxing conversion happens and that can add some memory and run time overhead. All these problems can be overcome with careful coding, but I'm only demonstrating the basic concept here.)
since the HashMap compares for references this works.
Comparing for references also happens to be the biggest problem with this approach: the fact that the object is a 2d array of double does not matter - one could simply replace your map with
HashMap<Object,ElemProperties> elemProperties;
without losing any functionality.
A better approach would be making a class that represents 2D keys based on arrays of double:
class KeyDouble2D {
private final double[][] key;
public KeyDouble2D(double[][] key) {
// Make a copy of key into this.key
}
public boolean equals(Object other) {
// Ensure that other is KeyDouble2D, then compare key
// sizes, and finally compare arrays element-by-element.
// Make sure to use `Double.equals` method to avoid NaN != NaN problem.
}
public int hashCode() {
// Compute hash code as a sum of hash codes in 2D array
}
}
You can use this class for keys of your hash map:
HashMap<KeyDouble2D,ElemProperties> elemProperties = ...;
...
ElemProperties prop = elemProperties.get(new KeyDouble2D(exampleArray)).getProp1();
Note that one needs to be very careful when using arrays of double for hash keys, for the same reason why one needs to be careful when comparing doubles for equality.
Why not create a class DoubleWithProperties, and manipulate an array of this class, instead of using a hashmap?
class DoubleWithProperties {
double value;
ElemProperties props;
public DoubleWithProperties(double value, ElemProperties props){
...
}
}
DoubleWithProperties[][] array = new DoubleWithProperties[5][5];
I'm new to Java and have the following question:
Is there an easier way of making methods for each variable?
The meaning behind the question is:
Do I have to define a method that does the exact same thing as other methods except that they use different variable names and types?
I think the most common methods with the same problem are the get- and set-accessors:
They share the same structure, the only difference are the variable types and names.
In my following example, you need to know:
Variables varA-varD just represent the existance of multiple variables with various types and names.
The variable "inheritor" is special. I do NOT implement inheritance, but I DO have to verify that somewhere, maybe in the inheritor of the inheritor of the inheritor the same variable
has a value ("!= null"; in case of Lists, HashMaps, Enumerations, etc.)
or
has a value other than -2 (because 0 means nothing and -1 indicates "infinite" in my system, so I thought using -2 for indicating that the variable hasn't been set yet is a good idea; in case of Integers, Floats, Doubles, etc.).
I have verification methods...
...to check whether the variables have already been set (or not)
and for this reason the code is located
...outside of the setter because I have to check the variables even when they have not been set yet.
public class ExampleClass {
private int varA;
private String varB;
private ExampleEnum varC;
private List<OtherClass> varD;
//there are more variables here...
private ExampleClass inheritor;
public int getVarA() {
return varA;
}
public void setVarA(int varA) {
this.varA = varA;
}
public boolean validateVarA() {
//-2 is "not set" for Integers
if (varA == -2 && inheritor != null) {
return inheritor.getVarA() != -2;
} else {
return varA != -2;
}
}
//Do I have to define three methods for each variable?
//What if I had like 20 variables?!?
//I would need 60 methods altough every third one
//shares the same structure.
}
I needed some sort of "building plan" for a method:
public T getVar() {
return var;
}
public void setVar(T var) {
this.var = var;
}
public boolean verifyVar() {
//How would I get the invalid value for each type?
T invalidValue = ?;
if (var == invalidValue && inheritor != null) {
return inheritor.getVar() != invalidValue;
} else {
return var != invalidValue;
}
}
In the example above:
"Var" or "var" would be the variable name
and
"T" would be the type of var
I have no idea how I would get the invalid value...
Sorry in case I think too complicated and there is a simple answer to my question. Furthermore, I apologize for any grammar mistakes that may occur.
For generic getters and setters, there's always Map<String, Object>, but I'm pretty sure that's not what you want, so you should stick to the JavaBean conventions (as mentioned in the comments, any IDE would generate those for you and it makes total sense to have them according to OOP recommendations).
Any attempt to implement generic accessors would sooner or later become some java.util.Map with tones of reflection around it. If that's what you want, perhaps you should reconsider your model and switch your type-safe beans to some free-form types like map.
For validation, there's the javax.validation package (JSR-303).
I'm using Java 6.
Suppose I have a class which I would like to save its instances into a map. Later on I would like to retrieve instances using only the "key fields". I'll ignore field modifiers, getters, and setters for conciseness.
class A {
String field1;
String field2;
String field3;
String field4;
//more fields
public int hashCode(){
//uses only field1 and field2
}
public boolean equals(Object o){
//uses only field1 and field2
}
}
Since Java's standard API doesn't have the MultikeyMap and I don't want to use 3rd party libraries, I have a choice of
1) creating a new class KeyA to represent the key of a map
2) use A itself as the key and populate only the "key fields" when I need to retrieve objects from a map
3) nest the maps, e.g. HashMap<String, HashMap<String, A>>
4) other workarounds
What do people normally use and when?
Given your recent edit, you should be fine to use instances of class A as keys in this situation. Lookups will be done based on the semantics of equals() and hashCode(), so this will cause instances to be retrieved by only the "key fields". Hence the following code would work as you intend:
final Map<A, String> map = new HashMap<A, Object>();
final A first = new A("fe", "fi", "fo", "fum");
map.put(first, "success");
// later on
final A second = new A ("fe", "fi", "foo", "bar");
System.out.println(map.get(second)); // prints "success";
Having said that, your description of option 2 makes me a little concerned that this might not be the most sensible option. If you create a Map<A, String>, that's a mapping from instances of class A to strings. Yet your second point implies that you want to think of it as a mapping from pairs of key fields to strings. If you're going to usually look up values based on a couple of "raw" strings, then I'd advise against this. It feels wrong (to me), to create a "fake" instance of A just to do a lookup - so in this case, you probably should create a key class that embodies the pair of strings as described in option 1. (You could even embed instances of these within your A objects to hold the key fields).
There's a similar argument for or against option 3, too. If the strings really are conceptually hierarchical, then it might well make sense. For example, if field1 was Country, and field2 was Town, one could definitely argue that the nested maps make sense - you have a mapping from country, to the map of Town->A relations within that country. But if your keys don't naturally compose in this fashion (say, if they were (x, y) coordinates), this would again not be a very natural way to represent the data, and a single-level map from XYPoint to value would be more sensible. (Likewise, if you never use the two-level map except to always go straight through both layers, one could argue the one-level map still makes more sense.)
And finally, as for option 4 -if you're always mapping to A itself, and storing the key as its own value (e.g. if you want to canonicalise your A instances, a bit like String.intern()) then as was pointed out you needn't use a Map at all, and a Set will do the job here. The Map is useful when you want to establish relationships between different objects, whereas a Set automatically gives you the uniqueness of objects without any extra conceptual overhead.
If you do use the class itself as a key, be warned though that objects should only generally be used as keys if their hashCode (and the behaviour of equals) won't change over time. Typically this means the keys are immutable, though here you could afford to have mutable "non-key" fields. If you were to break this rule, you'd see odd behaviour such as the following:
// Populate a map, with an A as the key
final Map<A, String> map = new HashMap<A, Object>();
final A a = new A("one", "two", "three", "four");
map.put(a, "here");
// Mutate a
a.setField1("un");
// Now look up what we associated with it
System.out.println(map.get(a)); // prints "null" - huh?
System.out.println(map.containsKey(a)); // prints "false"
I'd create an Index class, something like this (warning: untested code), to abstract out the indexing functionality. Why Java doesn't have something like this already is puzzling to me.
interface Indexer<T, K>
{
/** extract key from index */
public K getIndexKey(T object);
}
class Index<T,K>
{
final private HashMap<K,List<T>> indexMap = new HashMap<K,List<T>>();
final private Indexer<T,K> indexer;
public Index(Indexer<T,K> indexer)
{
this.indexer = indexer;
}
public void add(T object) {
K key = this.indexer.getIndexKey(object);
List<T> values = this.indexMap.get(key);
if (values == null)
{
values = new ArrayList<T>();
this.indexMap.put(key, values);
}
values.add(object);
}
public void remove(T object) {
K key = this.indexer.getIndexKey(object);
List<T> values = this.indexMap.get(key);
if (values != null)
{
values.remove(object);
}
}
public List<T> lookup(K key) {
List<T> values = this.indexMap.get(key);
return values == null
? Collections.emptyList()
: Collections.unmodifiableList(values);
}
}
example relevant to your class A:
Index<A,String> index1 = new Index<A,String>(new Indexer<A,String>() {
#Override public String getIndexKey(A object)
{
return object.field1;
}
});
Index<A,String> index2 = new Index<A,String>(new Indexer<A,String>() {
#Override public String getIndexKey(A object)
{
return object.field2;
}
});
/* repeat for all desired fields */
You would manually have to add and remove entries from the indices, but all the grungework below those operations is handled by the Index class.
Your class has "key fields". I would suggest to create a parent class, ParentA, with those key fields (which certainly map to a concept in your domain) and inherit this class in your child class A.
Override hashCode() and equals() in the ParentA class.
Use a Map<ParentA, A> to store your A instances and give the instance as key and value.
To retrieve a specific A instance, create a new ParentA instance, pA, with your key fields set, and do
A a = map.get(pA);
That's it.
Another way is to create a AIdentifier class with key fields and add an instance as A property id. So you add your instance with map.put(a.id, a); That's inheritance vs composition pattern discussion :)
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
How to "deep"-compare two objects that do not implement the equals method based on their field values in a test?
Original Question (closed because lack of precision and thus not fulfilling SO standards), kept for documentation purposes:
I'm trying to write unit tests for a variety of clone() operations inside a large project and I'm wondering if there is an existing class somewhere that is capable of taking two objects of the same type, doing a deep comparison, and saying if they're identical or not?
Unitils has this functionality:
Equality assertion through reflection, with different options like ignoring Java default/null values and ignoring order of collections
I love this question! Mainly because it is hardly ever answered or answered badly. It's like nobody has figured it out yet. Virgin territory :)
First off, don't even think about using equals. The contract of equals, as defined in the javadoc, is an equivalence relation (reflexive, symmetric, and transitive), not an equality relation. For that, it would also have to be antisymmetric. The only implementation of equals that is (or ever could be) a true equality relation is the one in java.lang.Object. Even if you did use equals to compare everything in the graph, the risk of breaking the contract is quite high. As Josh Bloch pointed out in Effective Java, the contract of equals is very easy to break:
"There is simply no way to extend an instantiable class and add an aspect while preserving the equals contract"
Besides what good does a boolean method really do you anyway? It'd be nice to actually encapsulate all the differences between the original and the clone, don't you think? Also, I'll assume here that you don't want to be bothered with writing/maintaining comparison code for each object in the graph, but rather you're looking for something that will scale with the source as it changes over time.
Soooo, what you really want is some kind of state comparison tool. How that tool is implemented is really dependent on the nature of your domain model and your performance restrictions. In my experience, there is no generic magic bullet. And it will be slow over a large number of iterations. But for testing the completeness of a clone operation, it'll do the job pretty well. Your two best options are serialization and reflection.
Some issues you will encounter:
Collection order: Should two collections be considered similar if they hold the same objects, but in a different order?
Which fields to ignore: Transient? Static?
Type equivalence: Should field values be of exactly the same type? Or is it ok for one to extend the other?
There's more, but I forget...
XStream is pretty fast and combined with XMLUnit will do the job in just a few lines of code. XMLUnit is nice because it can report all the differences, or just stop at the first one it finds. And its output includes the xpath to the differing nodes, which is nice. By default it doesn't allow unordered collections, but it can be configured to do so. Injecting a special difference handler (Called a DifferenceListener) allows you to specify the way you want to deal with differences, including ignoring order. However, as soon as you want to do anything beyond the simplest customization, it becomes difficult to write and the details tend to be tied down to a specific domain object.
My personal preference is to use reflection to cycle through all the declared fields and drill down into each one, tracking differences as I go. Word of warning: Don't use recursion unless you like stack overflow exceptions. Keep things in scope with a stack (use a LinkedList or something). I usually ignore transient and static fields, and I skip object pairs that I've already compared, so I don't end up in infinite loops if someone decided to write self-referential code (However, I always compare primitive wrappers no matter what, since the same object refs are often reused). You can configure things up front to ignore collection ordering and to ignore special types or fields, but I like to define my state comparison policies on the fields themselves via annotations. This, IMHO, is exactly what annotations were meant for, to make meta data about the class available at runtime. Something like:
#StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;
I think this is actually a really hard problem, but totally solvable! And once you have something that works for you, it is really, really, handy :)
So, good luck. And if you come up with something that's just pure genius, don't forget to share!
In AssertJ, you can do:
Assertions.assertThat(expectedObject).isEqualToComparingFieldByFieldRecursively(actualObject);
Probably it won't work in all cases, however it will work in more cases that you'd think.
Here's what the documentation says:
Assert that the object under test (actual) is equal to the given
object based on recursive a property/field by property/field
comparison (including inherited ones). This can be useful if actual's
equals implementation does not suit you. The recursive property/field
comparison is not applied on fields having a custom equals
implementation, i.e. the overridden equals method will be used instead
of a field by field comparison.
The recursive comparison handles cycles. By default floats are
compared with a precision of 1.0E-6 and doubles with 1.0E-15.
You can specify a custom comparator per (nested) fields or type with
respectively usingComparatorForFields(Comparator, String...) and
usingComparatorForType(Comparator, Class).
The objects to compare can be of different types but must have the
same properties/fields. For example if actual object has a name String
field, it is expected the other object to also have one. If an object
has a field and a property with the same name, the property value will
be used over the field.
Override The equals() Method
You can simply override the equals() method of the class using the EqualsBuilder.reflectionEquals() as explained here:
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
Just had to implement comparison of two entity instances revised by Hibernate Envers. I started writing my own differ but then found the following framework.
https://github.com/SQiShER/java-object-diff
You can compare two objects of the same type and it will show changes, additions and removals. If there are no changes, then the objects are equal (in theory). Annotations are provided for getters that should be ignored during the check. The frame work has far wider applications than equality checking, i.e. I am using to generate a change-log.
Its performance is OK, when comparing JPA entities, be sure to detach them from the entity manager first.
I am usin XStream:
/**
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object o) {
XStream xstream = new XStream();
String oxml = xstream.toXML(o);
String myxml = xstream.toXML(this);
return myxml.equals(oxml);
}
/**
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
XStream xstream = new XStream();
String myxml = xstream.toXML(this);
return myxml.hashCode();
}
http://www.unitils.org/tutorial-reflectionassert.html
public class User {
private long id;
private String first;
private String last;
public User(long id, String first, String last) {
this.id = id;
this.first = first;
this.last = last;
}
}
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
Hamcrest has the Matcher samePropertyValuesAs. But it relies on the JavaBeans Convention (uses getters and setters). Should the objects that are to be compared not have getters and setters for their attributes, this will not work.
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
import static org.junit.Assert.assertThat;
import org.junit.Test;
public class UserTest {
#Test
public void asfd() {
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertThat(user1, samePropertyValuesAs(user2)); // all good
user2 = new User(1, "John", "Do");
assertThat(user1, samePropertyValuesAs(user2)); // will fail
}
}
The user bean - with getters and setters
public class User {
private long id;
private String first;
private String last;
public User(long id, String first, String last) {
this.id = id;
this.first = first;
this.last = last;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirst() {
return first;
}
public void setFirst(String first) {
this.first = first;
}
public String getLast() {
return last;
}
public void setLast(String last) {
this.last = last;
}
}
If your objects implement Serializable you can use this:
public static boolean deepCompare(Object o1, Object o2) {
try {
ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
oos1.writeObject(o1);
oos1.close();
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
ObjectOutputStream oos2 = new ObjectOutputStream(baos2);
oos2.writeObject(o2);
oos2.close();
return Arrays.equals(baos1.toByteArray(), baos2.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Your Linked List example is not that difficult to handle. As the code traverses the two object graphs, it places visited objects in a Set or Map. Before traversing into another object reference, this set is tested to see if the object has already been traversed. If so, no need to go further.
I agree with the person above who said use a LinkedList (like a Stack but without synchronized methods on it, so it is faster). Traversing the object graph using a Stack, while using reflection to get each field, is the ideal solution. Written once, this "external" equals() and "external" hashCode() is what all equals() and hashCode() methods should call. Never again do you need a customer equals() method.
I wrote a bit of code that traverses a complete object graph, listed over at Google Code. See json-io (http://code.google.com/p/json-io/). It serializes a Java object graph into JSON and deserialized from it. It handles all Java objects, with or without public constructors, Serializeable or not Serializable, etc. This same traversal code will be the basis for the external "equals()" and external "hashcode()" implementation. Btw, the JsonReader / JsonWriter (json-io) is usually faster than the built-in ObjectInputStream / ObjectOutputStream.
This JsonReader / JsonWriter could be used for comparison, but it will not help with hashcode. If you want a universal hashcode() and equals(), it needs it's own code. I may be able to pull this off with a generic graph visitor. We'll see.
Other considerations - static fields - that's easy - they can be skipped because all equals() instances would have the same value for static fields, as the static fields is shared across all instances.
As for transient fields - that will be a selectable option. Sometimes you may want transients to count other times not. "Sometimes you feel like a nut, sometimes you don't."
Check back to the json-io project (for my other projects) and you will find the external equals() / hashcode() project. I don't have a name for it yet, but it will be obvious.
I think the easiest solution inspired by Ray Hulha solution is to serialize the object and then deep compare the raw result.
The serialization could be either byte, json, xml or simple toString etc. ToString seems to be cheaper. Lombok generates free easy customizable ToSTring for us. See example below.
#ToString #Getter #Setter
class foo{
boolean foo1;
String foo2;
public boolean deepCompare(Object other) { //for cohesiveness
return other != null && this.toString().equals(other.toString());
}
}
I guess you know this, but In theory, you're supposed to always override .equals to assert that two objects are truly equal. This would imply that they check the overridden .equals methods on their members.
This kind of thing is why .equals is defined in Object.
If this were done consistently you wouldn't have a problem.
A halting guarantee for such a deep comparison might be a problem. What should the following do? (If you implement such a comparator, this would make a good unit test.)
LinkedListNode a = new LinkedListNode();
a.next = a;
LinkedListNode b = new LinkedListNode();
b.next = b;
System.out.println(DeepCompare(a, b));
Here's another:
LinkedListNode c = new LinkedListNode();
LinkedListNode d = new LinkedListNode();
c.next = d;
d.next = c;
System.out.println(DeepCompare(c, d));
Apache gives you something, convert both objects to string and compare strings, but you have to Override toString()
obj1.toString().equals(obj2.toString())
Override toString()
If all fields are primitive types :
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
#Override
public String toString() {return
ReflectionToStringBuilder.toString(this);}
If you have non primitive fields and/or collection and/or map :
// Within class
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
#Override
public String toString() {return
ReflectionToStringBuilder.toString(this,new
MultipleRecursiveToStringStyle());}
// New class extended from Apache ToStringStyle
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.*;
public class MultipleRecursiveToStringStyle extends ToStringStyle {
private static final int INFINITE_DEPTH = -1;
private int maxDepth;
private int depth;
public MultipleRecursiveToStringStyle() {
this(INFINITE_DEPTH);
}
public MultipleRecursiveToStringStyle(int maxDepth) {
setUseShortClassName(true);
setUseIdentityHashCode(false);
this.maxDepth = maxDepth;
}
#Override
protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
if (value.getClass().getName().startsWith("java.lang.")
|| (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
buffer.append(value);
} else {
depth++;
buffer.append(ReflectionToStringBuilder.toString(value, this));
depth--;
}
}
#Override
protected void appendDetail(StringBuffer buffer, String fieldName,
Collection<?> coll) {
for(Object value: coll){
if (value.getClass().getName().startsWith("java.lang.")
|| (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
buffer.append(value);
} else {
depth++;
buffer.append(ReflectionToStringBuilder.toString(value, this));
depth--;
}
}
}
#Override
protected void appendDetail(StringBuffer buffer, String fieldName, Map<?, ?> map) {
for(Map.Entry<?,?> kvEntry: map.entrySet()){
Object value = kvEntry.getKey();
if (value.getClass().getName().startsWith("java.lang.")
|| (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
buffer.append(value);
} else {
depth++;
buffer.append(ReflectionToStringBuilder.toString(value, this));
depth--;
}
value = kvEntry.getValue();
if (value.getClass().getName().startsWith("java.lang.")
|| (maxDepth != INFINITE_DEPTH && depth >= maxDepth)) {
buffer.append(value);
} else {
depth++;
buffer.append(ReflectionToStringBuilder.toString(value, this));
depth--;
}
}
}}