How to clone `com.fasterxml.jackson.core.JsonParser` - java

I need to parse the same json stream twice, one time to identify say the length of array in the json stream, and next to parse the entities. However, there is only a single instance of JsonParser to start with. Is there a way I can clone this or create a copy of this because once the instance is used to parse, it can't be reused for re-parsing the same json stream obviously.
Thanks in advance.
Example:
static class ResultEntitiesContainer {
List<ResultEntity> resultEntities;
// getter and setters available
}
void parseEntities(JsonParser parser) {
// Need to extract number of entities.
int count=0;
ObjectMapper om = new ObjectMapper();
JsonNode node = om.readTree(parser);
node = node.get("resultEntities");
if (node.isArray()) {
count = node.size();
}
// Need to parse the entities in the json node
ResultEntitiesContainer rec = om.readValue(parser, ResultEntitiesContainer.class);
}

This answer aims to address the question of cloning the JsonParser assuming it is required.
com.fasterxml.jackson.core.JsonParser is a public abstract class and it does not provide a clone or similar method.
An abstract class may be extended by different implementations that the author of JsonParser.java has no control of.
Similarly it is not safe to clone a JsonParser as an argument of void parseEntities(JsonParser parser); because the author of parseEntities cannot be sure which implementation is used and whether it can be cloned.
However if you (as the author of parseEntities) do have control over the used implementations, then it is safe to clone the known implementations (assuming this is possible).
So if you do know which specific implementation (or implementations) of JsonParser your class will be using, you can try and clone specifically these known implementations.
E.g. add and implemented one or more methods (as needed) like:
void parseEntities(MyJsonParser parser);
void parseEntities(MyOtherJsonParser parser);
Then it is a question of cloning the specific implementations of JsonParser that are used. For instance assuming MyJsonParser supports cloning the following could be valid.
void parseEntities(MyJsonParser parser){
MyJsonParser clonedParser=parser.clone();//depends on implementation
...
}

As far as I can see, there is no need to parse twice. Just parse it once into an object of type ResultEntitiesContainer and count the elements in the list to get count. You could change method parseEntities as follows:
void parseEntities(JsonParser parser) {
ObjectMapper om = new ObjectMapper();
// Need to parse the entities in the json node
ResultEntitiesContainer rec = om.readValue(parser, ResultEntitiesContainer.class);
// Need to extract number of entities.
int count = rec.getResultEntities().size();
}
Alternatively you can parse to object ResultEntitiesContainer from json node as follows:
ResultEntitiesContainer rec = om.treeToValue(node, ResultEntitiesContainer.class);
Remark:
Please double check if ResultEntitiesContainer should be static.

Related

Transform java class instance to primitive types only

I want to "flatten"/transform an instance from a given Java class to another instance containing primitive types only.
Every field from an object that is not already a primitive type will have to be flattened recursively too, so that the resulting object contains a flattened view of the original one, with primitive types only.
For example, given the following classes:
class Element {
int id_;
Position position_;
}
class Position {
int x_;
int y_;
}
The resulting instance would be of type:
class FlattenedElement {
int id_;
int x_;
int y_;
}
And I would expect such a behaviour:
Element e = new Person ( 42, new Position(0, 0) );
FlattenedElement fe = e.flatten();
Is there any tool/library able to do so?
Or do I need to write my own flattener, using the reflection API I take it?
-- edit following most comments --
I changed my example to avoid any confusion with String and byte (I won't have to deal with Strings).
I need to keep the semantics of the data in the resulting conversion. The output primitive types data will be directly involved in a parallel computation using OpenCL, which only understands primitive data types.
In other words, what I need is to break encapsulation to manipulate directly the primitive data types embedded in the class hierarchy.
You can do this, but you will need a third party library to create the new class, like Javaassist. To introspect the class to be flattened, you will use reflection as some users already said. Here is another example that I wrote for you:
public static Class flatten( Class classToFlatten ) {
for ( Field f : classToFlatten.getDeclaredFields() ) {
Class type = f.getType();
String name = f.getName();
int modifiersConfig = f.getModifiers();
// extract all modifiers here (using the isXXX methods of the Modifier class)
System.out.print( Modifier.isPrivate( modifiersConfig ) ? "private" : "" );
System.out.print( " " + type );
System.out.print( " " + name );
System.out.println();
if ( type.isPrimitive() ) {
// primitive type.
// does not need to be converted.
// insert in the new class as it is (using Javaassist).
} else {
// no primitive type.
// needs to be converted and tested.
// insert in the new class after the conversion (using Javaassist).
// convert rules...
switch ( type.getSimpleName() ) {
case "String":
// insert in the new class a array of chars.
break;
// cases to test if the field is a wrapper (Integer, Long, etc.).
// other rules tha you need here...
}
// here you need to use recursion...
// you can use this method, but you will need to create
// a new parameter, passing the class that is been built
// to insert new fields in it (relative to the type that is been
// reflected)
}
}
// return the new class here and outside the method, use the newInstance
// method to create new instances of this class
return null;
}
With this I think you will be able to do what you need, but I thinking why you need this. You will have some problems when you have arrays of some type that will be recursively flettened, because you will maybe need to "backtrack" to resolve their type or to run the flatten algorithm some times. With generics, inner classes, methods and all kinds of class members you will have the same problem. I'm not sayng that this is impossible, but it will consume a lot of your time and maybe you could solve your problem in a simpler way as some users already said. Well, I hope you can do what you need and I want to know the results if possible! Maybe your solution can be the seed of a new library! Ok, enought of brainstorming :D Here are some links.
The Javaassist library can be downloaded here.
Here you can see a simple tutorial. I suggest that you use it only to begin, because the Javaassist API may have been improved since the creation of the tutorial, so, after reading this, refactor your code (if possible), reading the library docs.
Well, from my POV, one way would be this:
public class Person {
String name;
Atring address;
public FlattenedPerson flatten() {
FlattenedPerson fp = new FlattenedPerson(this.name.getBytes(), this.houseNumber, this.address.getStreet.getBytes(), this.address.getTown.getBytes());
return fp;
}
}
You have to use Reflection
Have a look at the little sample, return Field's name.
So to get the value of this Field you have to return f[i].get(Object)

How do I peek in a java serialized object?

I have an object from old Java code, and I now changed the serialized object code. I want to be able to read both the old files and the new files. I need a branching statement in readObject to do something like:
if (next object is int -- just poking, it might be an Object)
{
// we know we are in version 1
} else {
// read new version of object
}
is that possible to do?
Ok so basically the question is "How can we check with an ObjectInputStream whether the next field is a primitive or an object?" and the answer as far as I can see is: You can't.
Which means the best solution I can see to keep backwards compatibility is to never remove primitives from the original version - keeping useless information blows up the size a bit, but otherwise that's easy.
To add new fields, I can see two ways:
Keep the earlier message format identical and only add new objects at the end - you can then easily distinguish different versions by the message size (or more exactly you'll get an IOException when reading data of v2 when you get a v1 object). That's much simpler and generally preferred.
You can change objects from v1 to v2 and then do a simple instanceof check. If you want to add primitives is to store their wrapper versions (i.e. Integer et al). Can save you some bytes, but Java's serialization protocol was never efficient to begin with, so really that's unnecessary complicated.
if (object instanceof Integer) {
... Do stuff
} else {
... Do other stuff
}
EDIT: I suppose I should expand on this. You can check object types using instanceof but I'm not sure about being able to work with primatives like int or char.
The easiest way to do this is to keep the old member variables with their old types and add new member variables for new types. also, you must keep the serialVersionUID of the class the same. then, your readObject() implementation can do any necessary manipulation to transform the old data to new data.
Original Object:
public class MyObject {
private static final long serialVersionUID = 1234L;
private int _someVal;
}
New version:
public class MyObject {
private static final long serialVersionUID = 1234L;
private int _someVal; //obsolete
private String _newSomeVal;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
if(_someVal != 0) {
// translate _someVal to _newSomeVal
}
}
}
I believe there are more complex options available as well using custom ObjectStreamField[] serialPersistentFields, ObjectInputStream.GetField and ObjectOutputStream.PutField.
ObjectInputStream will load and create an instance of the right class.
object = ois.readObject();
if (object instanceof YourNewShiny ){
// new style object
} else if (object instanceof YourOldBusted ){
// convert YourOldBusted to YourNewShiny
} else {
throw new ToyOutOfPram();
}
This is all great if you have a new class, but if you have changed your class in an incompatible manner such that the ObjectInputStream cannot deserialise the old versions of the class into the new form. If this is the case you are pretty much stuffed.
Options:
Revert your changes, and either do them compatibly i.e. add a serialVersionId, don't change the order of fields, only add new field, plus don't assume not null constraints
Using an old version of the code read the serialised data, convert it to some intermediate form (xml,csv,etc) and then import this data into the new class definition and serialise it out
manually re implement the ObjectInputStream to detect your class type (you can use the serialVersionId to stiff the type)
Only the first seems like a good idea to me.

Converting any object to a byte array in java

I have an object of type X which I want to convert into byte array before sending it to store in S3. Can anybody tell me how to do this? I appreciate your help.
What you want to do is called "serialization". There are several ways of doing it, but if you don't need anything fancy I think using the standard Java object serialization would do just fine.
Perhaps you could use something like this?
package com.example;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Serializer {
public static byte[] serialize(Object obj) throws IOException {
try(ByteArrayOutputStream b = new ByteArrayOutputStream()){
try(ObjectOutputStream o = new ObjectOutputStream(b)){
o.writeObject(obj);
}
return b.toByteArray();
}
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
try(ByteArrayInputStream b = new ByteArrayInputStream(bytes)){
try(ObjectInputStream o = new ObjectInputStream(b)){
return o.readObject();
}
}
}
}
There are several improvements to this that can be done. Not in the least the fact that you can only read/write one object per byte array, which might or might not be what you want.
Note that "Only objects that support the java.io.Serializable interface can be written to streams" (see java.io.ObjectOutputStream).
Since you might run into it, the continuous allocation and resizing of the java.io.ByteArrayOutputStream might turn out to be quite the bottle neck. Depending on your threading model you might want to consider reusing some of the objects.
For serialization of objects that do not implement the Serializable interface you either need to write your own serializer, for example using the read*/write* methods of java.io.DataOutputStream and the get*/put* methods of java.nio.ByteBuffer perhaps together with reflection, or pull in a third party dependency.
This site has a list and performance comparison of some serialization frameworks. Looking at the APIs it seems Kryo might fit what you need.
Use serialize and deserialize methods in SerializationUtils from commons-lang.
Yeah. Just use binary serialization. You have to have each object use implements Serializable but it's straightforward from there.
Your other option, if you want to avoid implementing the Serializable interface, is to use reflection and read and write data to/from a buffer using a process this one below:
/**
* Sets all int fields in an object to 0.
*
* #param obj The object to operate on.
*
* #throws RuntimeException If there is a reflection problem.
*/
public static void initPublicIntFields(final Object obj) {
try {
Field[] fields = obj.getClass().getFields();
for (int idx = 0; idx < fields.length; idx++) {
if (fields[idx].getType() == int.class) {
fields[idx].setInt(obj, 0);
}
}
} catch (final IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
Source.
As i've mentioned in other, similar questions, you may want to consider compressing the data as the default java serialization is a bit verbose. you do this by putting a GZIPInput/OutputStream between the Object streams and the Byte streams.
To convert the object to a byte array use the concept of Serialization and De-serialization.
The complete conversion from object to byte array explained in is tutorial.
http://javapapers.com/core-java/java-serialization/
Q. How can we convert object into byte array?
Q. How can we serialize a object?
Q. How can we De-serialize a object?
Q. What is the need of serialization and de-serialization?

Generic object serialization in Jackson with Java

I would like to read in the string {"a": 1.0} as a generic Java Object while keeping the same string format. However, when I try, Jackson automatically changes the internal representation to {a = 1}. In other words, how can I get the following code to print {"a": 1.0} instead of {a = 1}? Note that, I have to read it in as an Object (due to other program constraints).
import org.codehaus.jackson.map.ObjectMapper;
public class Main {
public static void main(String[] args) {
try
{
ObjectMapper mapper = new ObjectMapper();
Object myObject = mapper.readValue("{\"a\": 1.0}", Object.class);
System.out.println(myObject.toString());
}
catch (Exception e)
{
e.printStackTrace();
System.err.println(e.getMessage());
}
}
}
The created object will be a map (like the other comments) and so its toString produces what you're seeing, {a = 1}. To get your code to print something closer to your input value, you need to use Jackson to write it back out with something like:
System.out.println(mapper.writeValueAsString(myObject));
That gives me what I believe you're looking for:
{"a":1.0}
In other words, Jackson has deserialized your input string into an arbitrary Java object. When you call toString on the object, its own toString is, of course, used. This can write the object however it pleases, including using the method from Object. To reproduce the input string, you have to use Jackson to serialize our object back out.
You need an existing class that matches the desired json structure. Object is not such class. You can still refer to it as Object, if that's needed:
Object myObject = mapper.readValue("{\"a\": 1.0}", SomeClass.class);
If you use a debugger, you will see that the type of the returned Object is LinkedHashMap. So what you see is the output of LinkedHashMap.toString(). There's no way for Jackson to change that, so you can either cast it to a Map and create the String yourself or ask for another return type that generates the JSON String for you:
if(myObject instanceof Map<?, ?>){
final Map<?, ?> map = (Map<?, ?>) myObject;
final StringBuilder sb = new StringBuilder("{");
boolean first = true;
for(final Entry<?, ?> entry : map.entrySet()){
if(first){
first = false;
} else{
sb.append(",");
}
sb.append("\n\t'")
.append(entry.getKey())
.append("':'")
.append(entry.getValue())
.append("'");
}
if(!first){
sb.append("\n");
}
sb.append("}");
System.out.println(sb.toString());
} else{
System.out.println(myObject);
}
Output:
{
'a':'1.0'
}
When Jackson is told to bind JSON into Object.class, it does just that; but since it has no a priori knowledge of what might be in that JSON (or what classes one might want to use), it has to use most basic Java types: Maps, Lists, Numbers, Booleans and Strings. So any JSON Object is represented by Map; JSON Array by List, and so on.
If you want a custom object, you must specify its type; or, when serializing, enable inclusion of explicit type information ("polymorphic type handling"). This will add either class name, or type name, and can be used to deserialize back to exact type.
To do this, either type itself (or one of its supertypes) must use #JsonTypeInfo annotation; or, if it is an Object property, #JsonTypeInfo for property (field or method).

Is there a Java utility to do a deep comparison of two objects? [closed]

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--;
}
}
}}

Categories

Resources