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