[ http://issues.apache.org/jira/browse/JCR-320?page=all ]
Jukka Zitting updated JCR-320: ------------------------------ Fix Version/s: (was: 1.1) > BinaryValue equals fails for two objects with two different byte arrays that > contain the same bytes. > ---------------------------------------------------------------------------------------------------- > > Key: JCR-320 > URL: http://issues.apache.org/jira/browse/JCR-320 > Project: Jackrabbit > Issue Type: Bug > Components: core > Affects Versions: 0.9, 1.0, 1.0.1 > Reporter: Piyush Purang > Assigned To: Jukka Zitting > Priority: Minor > > http://svn.apache.org/repos/asf/incubator/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/BinaryValue.java > Here is the present implementation > public boolean equals(Object obj) { > if (this == obj) { > return true; > } > if (obj instanceof BinaryValue) { > BinaryValue other = (BinaryValue) obj; > if (text == other.text && stream == other.stream > && streamData == other.streamData) { > return true; > } > // stream, streamData and text are mutually exclusive, > // i.e. only one of them can be non-null > if (stream != null) { > return stream.equals(other.stream); > } else if (streamData != null) { > return streamData.equals(other.streamData); > } else { > return text.equals(other.text); > } > } > return false; > } > Here are the problems with the present implementation > 1. streamData.equals(other.streamData ) will fail miserably. > 2. too many return statements! I guess no one ran a checkstyle on it. > 3. return stream.equals(other.stream); will always be false unless both have > been created with the same InputStream! > I wrote some testcases in SetValueBinaryTest > public void testBinaryValueEquals() throws Exception { > BinaryValue binaryValue1 = null; > BinaryValue binaryValue2 = null; > // initialize some binary value > data = createRandomString(10).getBytes(); > binaryValue1 = (BinaryValue) > superuser.getValueFactory().createValue(new ByteArrayInputStream(data)); > binaryValue2 = (BinaryValue) superuser.getValueFactory > ().createValue(new ByteArrayInputStream(data)); > //ideallly setup a test harness that tests all the cases as defined > by the contract in Object.equals() > assertTrue( binaryValue1.equals(binaryValue2)); > assertTrue( binaryValue1.equals(binaryValue1)); > assertFalse( binaryValue1.equals(null)); > } > public void testBinaryValueEquals2() throws Exception { > String str = createRandomString(10); > BinaryValue binaryValue1 = new BinaryValue(str.getBytes()); > BinaryValue binaryValue2 = new BinaryValue(str.getBytes()); > assertTrue( binaryValue1.equals(binaryValue2)); > assertTrue( binaryValue1.equals(binaryValue1)); > assertFalse( binaryValue1.equals(null)); > } > > public void testBinaryValueEquals3() throws Exception { > String str1 = "Some string xyz"; > String str2 = new StringBuffer().append("Some string xyz").toString(); > BinaryValue binaryValue1 = new BinaryValue(str1); > BinaryValue binaryValue2 = new BinaryValue(str2); > assertTrue( binaryValue1.equals(binaryValue2)); > assertTrue( binaryValue1.equals(binaryValue1)); > assertFalse( binaryValue1.equals(null)); > } > They were written quickly but with the present implementation the first two > fail at the very first assert* statement which for stream I can understand > (as we are basically propogating InputStream's equals contract) but for byte > arrays I can't agree with this behaviour unless it is so intended. It behaves > the best when BinaryVlaue wraps a string i.e. testBinaryValueEquals3() > passes without trouble. > I propose a new implementation where I am not very convinced with the > behaviour when we have streams being wrapped. If it should fail for the > streams then we should change the documentation for the method. As for making > it work right when streams are involved .. well the streams will have to be > read and compared. > > public boolean equals(Object obj) { > boolean result = false; > if (this == obj) { > result = true; > } else if (obj instanceof BinaryValue) { > BinaryValue other = (BinaryValue) obj; > // only one of text, stream and streamData are set at any given > point > if (text != null) { > result = text.equals(other.text); > } else if (stream != null) { > result = stream.equals(other.stream); > } else if (streamData != null) { > result = Arrays.equals(streamData, other.streamData); > } else { > // all values are null; test that the other object (which > could be us) > // also has everything set to null! > result = (other.text == null && other.stream == null > && other.streamData == null); > } > } > return result; > } > This implementation of course fails at the first assert* of the first test > method testBinaryValueEquals (It will pass the other two assert*s). > And if this new implementation doesn't fit the bill and an alternative isn't > needed then just skip implementing equals. > One more thought running through my mind is - if text, stream and data are > mutually exclusive why don't we have different classes for each of them? (Try > and wrap a stringValue into a binary value...) > I have also noticed that the hashCodes all return 0's throughtout the > package. In the case that the hashCode can't keep up with the contract of > equal I would propose throwing an UnsupportedOpertaionException. And if not > then declare it in the BasValue as it will be inherited (unless this leads > the QA tools to report infringement of the rule that when you define equals > you need to redefine hashCode - checkstyle does that). > The value package doesn't have any tests for it.. or did I miss them? -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira