Bug 338334 - equals() not working as expected for some units
Summary: equals() not working as expected for some units
Status: RESOLVED FIXED
Alias: None
Product: UOMo
Classification: Technology
Component: Units (show other bugs)
Version: 0.6.0   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Werner Keil CLA
QA Contact:
URL:
Whiteboard:
Keywords: api, example, helpwanted
Depends on:
Blocks:
 
Reported: 2011-02-27 08:59 EST by Werner Keil CLA
Modified: 2021-02-28 13:31 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Werner Keil CLA 2011-02-27 08:59:52 EST
Running UOMo Examples, the following occurs:
		MassAmount mass = new MassAmount(1000, SI.GRAM);
		MassAmount mass2 = new MassAmount(1, SI.KILOGRAM);
		mass.equals(mass2) returns false
		
This is a heritage from earlier JSR-275 implementations, where similar code produces the same result:
		Measure mass = Measure.valueOf(1000, SI.GRAM);
		Measure mass2 = Measure.valueOf(1, SI.KILOGRAM);
		mass.equals(mass2) is false
		
Same result for KILOGRAM.equals(KILO(GRAM));

The problem is related to how subclasses of AbstractUnit currently are compared. KILOGRAM is per definition "The base unit for mass quantities..." thus its type is BaseUnit. While results of other unit arithmetics including GRAM are multiples or sub-multiples of it. Making them TransformedUnit, ProductUnit or similar. Thus a BaseUnit has to be compared to those more detailed, trying to decompose the "unit-tree" in some cases.

The problem is pretty much identified, any help or input greatly appreciated.
Comment 1 Urs Reupke CLA 2011-06-17 08:34:24 EDT
The same problem occurs using the prefix notation.
Here's a test case:

@Test
public void kiloIsAThousand() {
   BaseAmount<Power> w2000 = new BaseAmount<Power>(2000, SI.WATT);
   BaseAmount<Power> kW2 = new BaseAmount<Power>(2, Prefix.KILO(SI.WATT));
   assertThat(w2000, is(kW2));
}
Comment 2 Werner Keil CLA 2011-11-26 06:37:31 EST
The problem goes a bit deeper, although I started addressing it in some classes already.

Take this test case with 2 subclasses of Number from the JDK:
	@Test
	public void testInteger() {
		Number n1 = Integer.valueOf(2);
		Number n2 = BigInteger.valueOf(2);
		assertThat(n1, is(n2));
	}
	
The test FAILS with a rather stupid
java.lang.AssertionError: 
Expected: is <2>
     got: <2>

	at org.junit.Assert.assertThat(Assert.java:778)
	at org.junit.Assert.assertThat(Assert.java:736)
	at org.eclipse.uomo.examples.units.console.EqualsTest.testInteger(EqualsTest.java:16)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

One would expect them to behave the same based on the value, but the class name/package are also taken into consideration. Same thing happened so far in UOMo and as it seems many other cases.
Comment 3 Werner Keil CLA 2013-04-28 09:35:23 EDT
Most of this is an underlying Java problem.
see @Test
	public void testInteger() {
		Number n1 = Integer.valueOf(2);
		Number n2 = BigInteger.valueOf(2);
		assertThat(n1, is(n2));
	}

We'll try to address this in UOMo in some cases, but in others we may not be able to overcome more general problems of the Java language and platform without changes being made there.