Fix/payara4003 Inaccessible constructor with @ConstructorProperties (#280)
* Support for @ConstructorProperties as proposed in jsonb-api/issues/115
https://github.com/eclipse-ee4j/jsonb-api/issues/115#issue-398276491
Signed-off-by: Johannes <johnnyt@gmx.at>
* Added missing final keywords. Flag for generic serializers/adapters moved to ComponentMatcher.
Signed-off-by: Roman Grigoriadi <roman.grigoriadi@oracle.com>
* Update module-info.java
Added required module for ConstructorProperties-Annotation
Signed-off-by: Johannes <johnnyt@gmx.at>
* Update pom.xml
Added required module for ConstructorProperties-Annotation
Signed-off-by: Johannes <johnnyt@gmx.at>
* formatting
Signed-off-by: Johannes <johnnyt@gmx.at>
* Merged changes from original repository
Signed-off-by: Johannes <johnnyt@gmx.at>
* Support for @ConstructorProperties as proposed in jsonb-api/issues/115
Signed-off-by: Johannes <johnnyt@gmx.at>
* Add builtin serializer for java.sql.Timestamp
* Further tests, reset formatting
Signed-off-by: Johannes <johnnyt@gmx.at>
* fix for https://github.com/payara/Payara/issues/4003
Signed-off-by: Johannes <johnnyt@gmx.at>
* test fixture names reverted back
Signed-off-by: Johannes <johnnyt@gmx.at>
* Added one currently ignored unit test for discussion
Signed-off-by: Johannes <johnnyt@gmx.at>
* removed message key for info log.
Signed-off-by: Johannes <johnnyt@gmx.at>
diff --git a/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
index b45e5c1..601ca4f 100644
--- a/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
+++ b/src/main/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospector.java
@@ -4,16 +4,17 @@
import org.eclipse.yasson.internal.model.JsonbCreator;
import org.eclipse.yasson.internal.properties.MessageKeys;
import org.eclipse.yasson.internal.properties.Messages;
-import org.eclipse.yasson.spi.JsonbComponentInstanceCreator;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
+import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
+import java.util.Arrays;
import java.util.logging.Logger;
class ConstructorPropertiesAnnotationIntrospector {
- private static final Logger LOG = Logger.getLogger(JsonbComponentInstanceCreator.class.getName());
+ private static final Logger LOG = Logger.getLogger(ConstructorPropertiesAnnotationIntrospector.class.getName());
private final JsonbContext jsonbContext;
private final AnnotationFinder constructorProperties;
@@ -43,6 +44,12 @@
if (!(properties instanceof String[])) {
continue;
}
+ if (!Modifier.isPublic(constructor.getModifiers())) {
+ String declaringClass = constructor.getDeclaringClass().getName();
+ String message = "The constructor of {0} annotated with @ConstructorProperties {1} is not accessible and will be ignored.";
+ LOG.finest(String.format(message, declaringClass, Arrays.toString((String[]) properties)));
+ continue;
+ }
if (jsonbCreator != null) {
// don't fail in this case, because it is perfectly allowed to have more than one
// @ConstructorProperties-Annotation in general.
diff --git a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java
index 5dda126..d8b4a0e 100644
--- a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java
+++ b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java
@@ -7,8 +7,10 @@
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedConstructor;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedFactoryMethod;
-import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithMissingConstructorAnnotation;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedProtectedConstructor;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithTwoJsonbCreatorAnnotatedSpots;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithoutAnnotatedConstructor;
import org.eclipse.yasson.internal.model.JsonbCreator;
import javax.json.bind.JsonbConfig;
@@ -16,6 +18,8 @@
import javax.json.spi.JsonProvider;
+import org.hamcrest.core.IsInstanceOf;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -60,6 +64,23 @@
}
@Test
+ public void testJsonbAnnotatedProtectedConstructorLeadsToAnException() {
+ exception.expect(JsonbException.class);
+ exception.expectCause(IsInstanceOf.instanceOf(IllegalAccessException.class));
+ JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedProtectedConstructor.class);
+ assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedProtectedConstructor.example(), creator);
+ }
+
+ // TODO Under discussion: https://github.com/eclipse-ee4j/yasson/issues/326
+ @Ignore
+ @Test
+ public void testNoArgConstructorShouldBePreferredOverUnusableJsonbAnnotatedProtectedConstructor() {
+ JsonbCreator creator = instrospector.getCreator(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.class);
+ assertParameters(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.parameters(), creator);
+ assertCreatedInstanceContainsAllParameters(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.example(), creator);
+ }
+
+ @Test
public void testMoreThanOneAnnotatedCreatorMethodShouldLeadToAnException() {
exception.expect(JsonbException.class);
exception.expectMessage("More than one @" + JsonbCreator.class.getSimpleName());
@@ -68,7 +89,7 @@
@Test
public void testCreatorShouldBeNullOnMissingConstructorAnnotation() {
- assertNull(instrospector.getCreator(ObjectWithMissingConstructorAnnotation.class));
+ assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class));
}
}
\ No newline at end of file
diff --git a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTestFixtures.java b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTestFixtures.java
index c58273b..aa711a5 100644
--- a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTestFixtures.java
+++ b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTestFixtures.java
@@ -43,10 +43,7 @@
return new ObjectWithoutAnnotatedConstructor("a string", Long.MAX_VALUE);
}
- @JsonbCreator
- public ObjectWithoutAnnotatedConstructor( //
- @JsonbProperty("string") String aString, //
- @JsonbProperty("primitive") long aPrimitive) {
+ public ObjectWithoutAnnotatedConstructor(String aString, long aPrimitive) {
this.string = aString;
this.primitive = aPrimitive;
}
@@ -93,6 +90,88 @@
}
}
+ public static class ObjectWithJsonbCreatorAnnotatedProtectedConstructor implements ProvidesParameterRepresentation {
+ private final String string;
+ private final long primitive;
+
+ public static final Map<String, Type> parameters() {
+ return twoParameters("string", String.class, "primitive", long.class);
+ }
+
+ public static final ProvidesParameterRepresentation example() {
+ return new ObjectWithJsonbCreatorAnnotatedProtectedConstructor("a string", Long.MAX_VALUE);
+ }
+
+ @JsonbCreator
+ protected ObjectWithJsonbCreatorAnnotatedProtectedConstructor( //
+ @JsonbProperty("string") String aString, //
+ @JsonbProperty("primitive") long aPrimitive) {
+ this.string = aString;
+ this.primitive = aPrimitive;
+ }
+
+ @Override
+ public Object[] asParameters() {
+ return new Object[] { string, primitive };
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectWithJsonbCreatorAnnotatedProtectedConstructor [string=" + string + ", primitive=" + primitive + "]";
+ }
+ }
+
+ public static class ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor implements ProvidesParameterRepresentation {
+ private String string;
+ private long primitive;
+
+ public static final Map<String, Type> parameters() {
+ return twoParameters("string", String.class, "primitive", long.class);
+ }
+
+ public static final ProvidesParameterRepresentation example() {
+ return new ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor("a string", Long.MAX_VALUE);
+ }
+
+ public ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor() {
+ super();
+ }
+
+ @JsonbCreator
+ protected ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor( //
+ @JsonbProperty("string") String aString, //
+ @JsonbProperty("primitive") long aPrimitive) {
+ this.string = aString;
+ this.primitive = aPrimitive;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ public long getPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(long primitive) {
+ this.primitive = primitive;
+ }
+
+ @Override
+ public Object[] asParameters() {
+ return new Object[] { string, primitive };
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor [string=" + string + ", primitive=" + primitive + "]";
+ }
+ }
+
public static class ObjectWithJsonbCreatorAnnotatedFactoryMethod implements ProvidesParameterRepresentation {
private final String string;
private final long primitive;
@@ -265,6 +344,161 @@
}
}
+ public static class ObjectWithPublicNoArgAndAnnotatedPrivateConstructor implements ProvidesParameterRepresentation {
+ private String string;
+ private Long primitive;
+
+ public static final Map<String, Type> parameters() {
+ return twoParameters("string", String.class, "primitive", long.class);
+ }
+
+ public static final ProvidesParameterRepresentation example() {
+ return new ObjectWithPublicNoArgAndAnnotatedPrivateConstructor(" ", Long.valueOf(-12));
+ }
+
+ public ObjectWithPublicNoArgAndAnnotatedPrivateConstructor() {
+ super();
+ }
+
+ @ConstructorProperties({ "string", "primitive" })
+ private ObjectWithPublicNoArgAndAnnotatedPrivateConstructor(String aString, long aPrimitive) {
+ this.string = aString;
+ this.primitive = aPrimitive;
+ }
+
+ public Long getPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(Long primitive) {
+ this.primitive = primitive;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ @Override
+ public Object[] asParameters() {
+ return new Object[] { string, primitive };
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectWithPublicNoArgAndAnnotatedPrivateConstructor [string=" + string + ", primitive=" + primitive + "]";
+ }
+ }
+
+ public static class ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor implements ProvidesParameterRepresentation {
+ private String string;
+ private Long primitive;
+
+ public static final Map<String, Type> parameters() {
+ return twoParameters("string", String.class, "primitive", long.class);
+ }
+
+ public static final ProvidesParameterRepresentation example() {
+ return new ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor(" ", Long.valueOf(-12));
+ }
+
+ public static final ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor create(String aString, long aPrimitive) {
+ return new ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor(aString, aPrimitive);
+ }
+
+ public ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor() {
+ super();
+ }
+
+ @ConstructorProperties({ "string", "primitive" })
+ ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor(String aString, long aPrimitive) {
+ this.string = aString;
+ this.primitive = aPrimitive;
+ }
+
+ public Long getPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(Long primitive) {
+ this.primitive = primitive;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ @Override
+ public Object[] asParameters() {
+ return new Object[] { string, primitive };
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor [string=" + string + ", primitive=" + primitive + "]";
+ }
+ }
+
+ public static class ObjectWithPublicNoArgAndAnnotatedProtectedConstructor implements ProvidesParameterRepresentation {
+ private String string;
+ private Long primitive;
+
+ public static final Map<String, Type> parameters() {
+ return twoParameters("string", String.class, "primitive", long.class);
+ }
+
+ public static final ProvidesParameterRepresentation example() {
+ return new ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor(" ", Long.valueOf(-12));
+ }
+
+ public static final ObjectWithPublicNoArgAndAnnotatedProtectedConstructor create(String aString, long aPrimitive) {
+ return new ObjectWithPublicNoArgAndAnnotatedProtectedConstructor(aString, aPrimitive);
+ }
+
+ @ConstructorProperties({ "string", "primitive" })
+ protected ObjectWithPublicNoArgAndAnnotatedProtectedConstructor(String aString, long aPrimitive) {
+ this.string = aString;
+ this.primitive = aPrimitive;
+ }
+
+ public ObjectWithPublicNoArgAndAnnotatedProtectedConstructor() {
+ super();
+ }
+
+ public Long getPrimitive() {
+ return primitive;
+ }
+
+ public void setPrimitive(Long primitive) {
+ this.primitive = primitive;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ @Override
+ public Object[] asParameters() {
+ return new Object[] { string, primitive };
+ }
+
+ @Override
+ public String toString() {
+ return "ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation [string=" + string + ", primitive=" + primitive + "]";
+ }
+ }
+
public static class ObjectWithMissingConstructorAnnotation implements ProvidesParameterRepresentation {
private final String string;
private final long primitive;
diff --git a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java
index 6ef7997..1dd2e92 100644
--- a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java
+++ b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java
@@ -6,7 +6,7 @@
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedConstructor;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedFactoryMethod;
-import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithMissingConstructorAnnotation;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithoutAnnotatedConstructor;
import org.eclipse.yasson.internal.model.JsonbCreator;
import javax.json.bind.JsonbConfig;
@@ -47,7 +47,7 @@
@Test
public void testCreatorShouldBeNullOnMissingConstructorAnnotation() {
- assertNull(instrospector.getCreator(ObjectWithMissingConstructorAnnotation.class));
+ assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class));
}
@Test
diff --git a/src/test/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospectorTest.java b/src/test/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospectorTest.java
index 5cd166f..4360f70 100644
--- a/src/test/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospectorTest.java
+++ b/src/test/java/org/eclipse/yasson/internal/ConstructorPropertiesAnnotationIntrospectorTest.java
@@ -8,6 +8,9 @@
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithConstructorPropertiesAnnotation;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedConstructor;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithPublicNoArgAndAnnotatedPrivateConstructor;
+import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithPublicNoArgAndAnnotatedProtectedConstructor;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithTwoConstructorPropertiesAnnotation;
import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithoutAnnotatedConstructor;
import org.eclipse.yasson.internal.model.JsonbCreator;
@@ -65,4 +68,21 @@
assertNull(creator);
}
+ @Test
+ public void testAnnotatedInaccessiblePrivateConstructorShouldBeIgnored() {
+ JsonbCreator creator = instrospector.getCreator(constructorsOf(ObjectWithPublicNoArgAndAnnotatedPrivateConstructor.class));
+ assertNull(creator);
+ }
+
+ @Test
+ public void testAnnotatedInaccessiblePackageProtectedConstructorShouldBeIgnored() {
+ JsonbCreator creator = instrospector.getCreator(constructorsOf(ObjectWithPublicNoArgAndAnnotatedPackageProtectedConstructor.class));
+ assertNull(creator);
+ }
+
+ @Test
+ public void testAnnotatedInaccessibleProtectedConstructorShouldBeIgnored() {
+ JsonbCreator creator = instrospector.getCreator(constructorsOf(ObjectWithPublicNoArgAndAnnotatedProtectedConstructor.class));
+ assertNull(creator);
+ }
}
\ No newline at end of file