comparing two XmlBeans Objects for equality - java

I've an XML Beans Interface called SynonymsRequest with:
public interface SynonymsRequest extends org.apache.xmlbeans.XmlObject {...}
I want to test two instances of SynonymsRequest for equality:
SynonymsRequest s1 = SynonymsRequest.Factory.newInstance();
s1.setQueryText("blub");
s1.setRequesterId(BigInteger.valueOf(1));
SynonymsRequest s2 = SynonymsRequest.Factory.newInstance();
s2.setQueryText("guck");
s2.setRequesterId(BigInteger.valueOf(1));
I've tried the following:
assertTrue(s1.equals(s2)); => assertion does not pass
assertEquals(0, s1.compareTo(s2)); => throws ClassCastException
assertEquals(0, s1.compareValue(s2)); => assertion does not pass (returns 2, not compareable)
assertTrue(s1.valueEquals(s2)); => always returns true, no matter if the two instances are equal
So what is the proper way of doing this?

If it doesn't impact the performance of your program, you could compare them like this:
assertTrue(s1.xmlText().equals(s2.xmlText()));
Otherwise, I guess you will have to write your own custom comparator.

As I understand, the comparison compares two simple values only. It cannot deduct your desired comparison algorithm.
Or I don't understand what exactly do you mean?

XmlBeans doesn't support a deep comparison so you'll have to write your own. There was a thread on the dev mailing list a while ago about a schema-aware comparison, but I'm not sure anything became of it:
http://www.mail-archive.com/dev#xmlbeans.apache.org/msg01960.html

Noticed this a while back - if the two objects have toString() methods generated when they were made, then you can to an .equals on the toString() methods of the objects. These can be compared with relativ ease, since they will check if the output xml is equivalent.

Related

JUnit - compare unknown Collection and ArrayList

I want to compare Collection (products) (in my case it is LinkedHashMap$LinkedValues) and ArrayList.
The test
assertThat(products, equalTo(Lists.newArrayList(product1, product2, product3)));
doesn't work because LinkedValues doesn't implement equals method.
So I changed my test to:
assertThat(new ArrayList<>(products), equalTo(Lists.newArrayList(product1, product2, product3)));
Is there a better solution where I do not have to check if the collection implements equals method?
Since you're using Hamcrest, you should use the slightly confusingly named method Matchers.contains(). It checks whether the target collection contains the same elements in the same order as the original collection.
Given
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("a", "A");
linkedHashMap.put("b", "B");
This will pass:
assertThat(linkedHashMap.values(), contains("A", "B"));
and this would fail:
assertThat(linkedHashMap.values(), contains("B", "A"));
Note that Hamcrest has been long dead and even though it works fine and is okay for 99% of usages, you will be shocked by how good AssertJ is, how much functionality it provides and how easy asserting can be.
With AssertJ:
assertThat(linkedHashMap.values()).containsExactly("A", "B");
Assuming the data type you're using already has an equals method, then there's no need to check for an (un-)implemented equals() function. Otherwise, you would have to create something that compares the data you're using.
On a side note, the two lines of code you have are identical. Did you mean to put something else in the second line?
You can use Arrays.equals:
assertTrue(Arrays.equals(products.toArray(), new Product[] {product1, product2, product3}));
This checks array sizes and odering of items. Your product class should implement equals() to be something meaningful.
Note that you can use ArrayList.toArray() to get an array if needed.

fj.data.Set comparison

In java.util, we can use the containsAll method to compare two java.util.Set. What's the best way to compare two fj.data.Set?
Is there really any "valuable" benefit of using fj over java.util?
I have never used that library nor will I ever, but looking through the API I found the method
public final boolean subsetOf(Set<A> s)
Returns true if this set is a subset of the given set.
Parameters: s - A set which is a superset of this set if this method returns true.
Returns: true if this set is a subset of the given set.
I believe this should be used like a "reversed" containsAll:
a.containsAll(b) is true i.f.f. b.subsetOf(a) is true (not sure how equal sets are handled, my guess is that it's fine).
Afterthought: I just noticed how fishy the wording in the javadoc is. The parameter description is dependent on the output: a superset of this set if this method returns true. You're not supposed to assume on the parameter or use a conditional for it. A better wording would be along the lines of: a set to be checked for being a superset.
To compare two sets use Set.subsetOf. So s1.subsetOf(s2) if s1 is a subset of s2 (in contains terms, s2 contains s1).
To create sets use Set.set which takes an ordering of elements (that is, how to know whether an item is less than another so the set can be stored in a red-black tree).
FunctionalJava uses the functional programming (FP) approach - data is immutable. That makes the Collection interface inappropriate for implementing. Note all the mutation and updating of objects in the Collection interface in methods like add, addAll, remove, etc.
There should be better support for converting to and from java.util.Set, but to convert a fj.data.Set to a java.util class, call set.toStream().toCollection() or set.toList().toJavaList().

How to test an array of objects with JUnit

Trying to check a method which adds a module object to an array works correctly. How do I write a JUnit test which tests to see if an object has indeed been added to the array?
Here is what I have so far:
#Test
public void testAddModule() {
Student chris = new Student("Chris", "1");
Module csc8001 = new Module("CSC8001", "Programming and data structures", 5, 5, 0, 7);
Module csc8002 = new Module("CSC8002", "Programming II", 5, 5, 0, 7);
chris.addModule(csc8001);
chris.addModule(csc8002);
Module [] expectedResult = {csc8001,csc8002};
ModuleRecord[] resultArray = Student.moduleRecords;
Assert.assertArrayEquals( expectedResult, resultArray );
}
The problem I have is the array is just storing references to the objects, how do I test to see if the array is storing the correct information?
You're on the right track: assertArrayEquals should work. The concept you're looking for is the difference between shallow equals ("==") and deep equals (".equals"), which is related to the difference between reference equality ("==") and object equality (".equals").
If two arrays have the same length, and contain the exact same primitive values and references, it's easy to say that they're equal: [0, 1] equals [0, 1] even if the arrays themselves are different objects, and the same happens for [csc8001, csc8002] and [csc8001, csc8002]. This is known as "shallow" equality, and it's very very fast to compute.
If you're actually looking to compare the objects using their equals methods, you need "deep" equality. This checks the proper number of entries, and checks that x[n].equals(y[n]) for all n. This may take longer, because Java can't just compare the references; it actually calls a method on the objects. This is only of value to you if you override equals, though; if your Module doesn't override equals it uses Object's built-in equals method, which acts the same way == does.
In any case, it's not very clear in the documentation, but Assert.assertArrayEquals calls Assert.internalArrayEquals, which basically does a deep comparison using .equals.
That leaves you with three options:
Keep using assertArrayEquals. That's what it's there for, and because equal references imply equal objects, it's the right thing to do.
Keep using assertArrayEquals but also write a Module.equals method to prove the data itself is identical. Remember, this is only an issue if you want to prove that two different instances behave as if they were equal based on their data, and you probably don't have to worry about that right now.
Break out what you're testing for, as Jason mentioned, which confirms that the data is correct without having you write an equals method:
assertEquals(2, resultArray.length);
Module addedModule = resultArray[1];
assertEquals("CSC8002", addedModule.code); /* ... */
If you ever do try overriding equals, be careful: You'll need to uphold some rules and you'll also need to override hashCode. Read more here.
The brute force method is to check that the array has the expected number of entries, then each object stored in the array has the expected attribute values.

Why assertEquals(new int[]{1}, new int[]{1}) results in failure?

I was testing my shuffling class and came across one issue I cannot understand. Why does the following assert statement:
assertEquals(new int[]{1}, new int[]{1});
results in an AssertionError? Naturally, the correct answer is "because they are not equal!", but could someone explain me why? And how to test a method, for which I would like the two such objects to be equal?
but could someone explain me why
Sure - arrays don't override equals, therefore they inherit the behaviour from Object, where any two distinct objects are non-equal.
It's even simpler than the version you showed if you use a 0-element array:
System.out.println(new int[0].equals(new int[0])); // false
That's why when checking for equality in non-test code you use Arrays.equals, and when checking for equality in test code you use a dedicated assertXyz method (where the exact method depends on the version of JUnit etc).
assertEquals calls the equals object in one of the objects to compare it with the other.
Arrays need to be compared using Arrays.equals() if you want a full comparison of the two arrays, otherwise unfortunately they just use the Object equals method.
See also: equals vs Arrays.equals in Java
Because you create 2 different objects and they point to different locations in the memory.
When comparing objects, you use the equals() method inherited from the class Object. Now, if you don't override the method in your class, you will have the default behaviour which is the comparison of objects address. In the code you create 2 arrays, but even though their content is the same, not the content is tested for being equal, but the objects reference by using the inherited equals() method from Object class.

Java string comparison is not working when concatenated with number

My question to java folks is, when I am comparing two strings
imageName=new String[20];
....
imageName[1]="img1";
imageName[2]="img1";
if(imageName[1]==imageName[2])
{
//// codes
}
it works perfectly, but when I am making the string through number concatenation it's not working
imageName=new String[20];
int j=1,k=1;
imageName[1]="img"+j;
imageName[2]="img"+k;
if(imageName[1].toString()==imageName[2].toString())
{
//// codes
}
it's not working though the values of j and k are the same
Thanks in advance for your solution
You should use String.equals when comparing two Strings:
if (imageName[1].equals(imageName[2])
You shouldn't compare strings with ==, but instead use the .equals method: imageName[1].equals(imageName[2]).
== compares the pointers for equality, so it'll be true if both variables represent the exact same instance in memory. In the first case, it's the case because Java pools String literals for performance. But in your second case, you're getting two distinct heap-allocated objects, which, despite their content is identical, are two distinct objects nonetheless.
You are comparing whether the two String are exactly the same object.
What you intended was to compare their contents. I suggest you use .equals instead.
Never, ever, use "==" to compare Strings in Java. Use the equals() method. The == operator checks to see if two String variables are referring to the same location in memory, while the equals() method checks whether two separate String objects contain the same characters. It's this second definition that makes sense here: your String concatenation is creating separate String objects, but we still want to consider them as "equal".
The correct way to compare strings is using equals() method
So, Please change your code as below,
if (imageName[1].equals(imageName[2])
And please consider to do a research in SO before posting, as the questions like this have been answered many times before.
== is a reference comparison. That is, you're determining if the two objects are, in fact, the same object. If you use equals() then that method comparses the contents of the string i.e. do those objects have the same contents (you'll appreciate there is a subtle difference here)
Your first scenario works since the compiler is clever enough to realise that you have the same string twice. i.e. it looks at:
imageName[1]="img1";
imageName[2]="img1";
and determines that your array elements can point to the same object. In your second scenario, that's no longer true.
imageName[1]="img"+j;
imageName[2]="img"+k;
The compiler can't reliably determine that these could be the same string object (quite correctly, too).
So (generally speaking) you should use equals() to compare Strings. You can use the reference equality (it's faster since it comparse the references rather than the string contents), but you have to be absolutely sure about what you're doing (perhaps you're using String.intern() - but there are disadvantages there)
To compare two Strings you better use equals() method
if(imageName[1].equals(imageName[2]))
{
//// codes
}

Categories

Resources