Skip to content

Commit

Permalink
Fix #111
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed May 5, 2019
1 parent 658b936 commit 63919af
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,9 @@ public abstract class ProviderBase<
// then some primitive types
DEFAULT_UNTOUCHABLES.add(new ClassKey(char[].class));

/* 27-Apr-2012, tatu: Ugh. As per
* [https://github.com/FasterXML/jackson-jaxrs-json-provider/issues/12]
* better revert this back, to make them untouchable again.
*/
// 27-Apr-2012, tatu: Ugh. As per
// [https://github.com/FasterXML/jackson-jaxrs-json-provider/issues/12]
// better revert this back, to make them untouchable again.
DEFAULT_UNTOUCHABLES.add(new ClassKey(String.class));
DEFAULT_UNTOUCHABLES.add(new ClassKey(byte[].class));
}
Expand Down Expand Up @@ -1058,7 +1057,7 @@ private final THIS _this() {
*/
private static NoContentExceptionSupplier _createNoContentExceptionSupplier() {
try {
Class cls = Class.forName(CLASS_NAME_NO_CONTENT_EXCEPTION);
Class<?> cls = Class.forName(CLASS_NAME_NO_CONTENT_EXCEPTION);
Constructor<?> ctor = cls.getDeclaredConstructor(String.class);
if (ctor != null) {
return new JaxRS2NoContentExceptionSupplier();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,38 @@ private final boolean _equals(Annotation[] otherAnn)
if (otherAnn.length != len) {
return false;
}
for (int i = 0; i < len; ++i) {
if (_annotations[i] != otherAnn[i]) {

// 05-May-2019, tatu: If we wanted to true equality of contents we should
// do order-insensitive check; however, our use case is not unifying all
// possible permutations but rather trying to ensure that caching of same
// method signature is likely to match. So false negatives are acceptable
// over having to do order-insensitive comparison.

switch (len) {
default:
for (int i = 0; i < len; ++i) {
if (!_annotations[i].equals(otherAnn[i])) {
return false;
}
}
return true;

case 3:
if (!_annotations[2].equals(otherAnn[2])) {
return false;
}
// fall through
case 2:
if (!_annotations[1].equals(otherAnn[1])) {
return false;
}
// fall through
case 1:
if (!_annotations[0].equals(otherAnn[0])) {
return false;
}
// fall through
case 0:
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.fasterxml.jackson.jaxrs.base;

public abstract class BaseTestBase
extends junit.framework.TestCase
{
// for now just placeholder
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.fasterxml.jackson.jaxrs.base.cfg;

import java.lang.annotation.Annotation;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.jaxrs.base.BaseTestBase;
import com.fasterxml.jackson.jaxrs.cfg.AnnotationBundleKey;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotEquals;

// for [jaxrs-providers#111]
public class AnnotationBundleKeyTest
extends BaseTestBase
{
// let's also test multiple annotation case
@JsonIgnoreProperties
@JsonPropertyOrder({ "a", "b" })
@JsonSerialize
@JsonDeserialize
static class Helper {
@JsonCreator
public Helper(@JsonProperty("x") int x) { }

@JsonValue
@JsonView(Object.class)
public int getX() { return 3; }

// A "copy" of `getX`
@JsonValue
@JsonView(Object.class)
public int altX() { return 3; }

@JsonPropertyOrder
@JsonView(Object.class)
public int notX() { return 4; }

public void setX(@JsonProperty("x") int x) { }
}

public void testWithClassAnnotations() throws Exception
{
_checkWith(Helper.class.getAnnotations(), Helper.class.getAnnotations());
}

public void testWithMethodAnnotationEquals() throws Exception
{
// First, same method parameters definitely should match
_checkWith(Helper.class.getDeclaredMethod("getX").getAnnotations(),
Helper.class.getDeclaredMethod("getX").getAnnotations());
// but so should annotations from different method as long as
// same parameters are in same order
_checkWith(Helper.class.getDeclaredMethod("getX").getAnnotations(),
Helper.class.getDeclaredMethod("altX").getAnnotations());
}

public void testWithMethodAnnotationDifferent() throws Exception
{
// However: not so with actually differing annotations
_checkNotEqual(Helper.class.getDeclaredMethod("getX").getAnnotations(),
Helper.class.getDeclaredMethod("notX").getAnnotations());
}

public void testWithMethodParameterAnnotation() throws Exception
{
_checkWith(Helper.class.getDeclaredMethod("setX", Integer.TYPE).getParameterAnnotations()[0],
Helper.class.getDeclaredMethod("setX", Integer.TYPE).getParameterAnnotations()[0]);
}

public void testWithConstructorAnnotation() throws Exception
{
_checkWith(Helper.class.getConstructor(Integer.TYPE).getAnnotations(),
Helper.class.getConstructor(Integer.TYPE).getAnnotations());
}

public void testWithConstructorParameterAnnotation() throws Exception
{
_checkWith(Helper.class.getConstructor(Integer.TYPE).getParameterAnnotations()[0],
Helper.class.getConstructor(Integer.TYPE).getParameterAnnotations()[0]);
}

protected void _checkWith(Annotation[] anns1, Annotation[] anns2) {
// First, sanity check2 to know we passed non-empty annotations, same by equality
if (anns1.length == 0) {
fail("Internal error: empty annotation array");
}
assertArrayEquals("Internal error: should never differ", anns1, anns2);

AnnotationBundleKey b1 = new AnnotationBundleKey(anns1, Object.class);
AnnotationBundleKey b2 = new AnnotationBundleKey(anns2, Object.class);

if (!b1.equals(b2) || !b2.equals(b1)) {
assertEquals(String.format("Implementations over %s backed annotations differ", anns1[0].getClass()),
b1, b2);
}
}

protected void _checkNotEqual(Annotation[] anns1, Annotation[] anns2) {
AnnotationBundleKey b1 = new AnnotationBundleKey(anns1, Object.class);
AnnotationBundleKey b2 = new AnnotationBundleKey(anns2, Object.class);

if (b1.equals(b2) || b2.equals(b1)) {
assertNotEquals(String.format("Implementations over %s backed annotations SHOULD differ but won't", anns1[0].getClass()),
b1, b2);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ public void testKeys() throws Exception
assertEquals(key1immutable, key1immutable);

assertEquals(key1.hashCode(), key1dup.hashCode());

// then inequality by content (even though both have 1 JSONP annotation)
assertFalse(key1.equals(key2));
assertFalse(key2.equals(key1));

// but safe copy ought to be equal
// Fixed with [jaxrs-providers#111]: SHOULD be equal:
assertTrue(key1.equals(key2));
assertTrue(key2.equals(key1));

// and safe copy ought to be equal
assertTrue(key1.equals(key1dup)); // from same method
assertTrue(key1dup.equals(key1));
assertTrue(key1.equals(key1immutable)); // and immutable variant
Expand Down
4 changes: 4 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ Tim Ward (timothyjward@github)

* Contributed #93: Jackson OSGi metadata is incomplete
(2.8.5)

John McCarthy (jvmccarthy@github)
* Reported #111: AnnotationBundleKey equality fails for Parameter Annotations
(2.10.0)
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Sub-modules:

2.10.0 (not yet released)

#111: AnnotationBundleKey equality fails for Parameter Annotations
(reported by John M)
- Add JDK9+ `module-info` with Moditect plugin

2.9.8 (15-Dec-2018)
Expand Down

0 comments on commit 63919af

Please sign in to comment.