diff --git a/DependencyUpdateSearch_Rules.xml b/DependencyUpdateSearch_Rules.xml
new file mode 100644
index 00000000..77cc7db8
--- /dev/null
+++ b/DependencyUpdateSearch_Rules.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ (?i).*Alpha(?:-?\d+)?
+ (?i).*a(?:-?\d+)?
+ (?i).*Beta(?:-?\d+)?
+ (?i).*-B(?:-?\d+)?
+ (?i).*RC(?:-?\d+)?
+ (?i).*CR(?:-?\d+)?
+ (?i).*M(?:-?\d+)?
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 4840503f..c0824ddf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,7 @@
junit
junit
- 4.12
+ 4.13.2
test
@@ -52,32 +52,38 @@
com.fasterxml.jackson.core
jackson-annotations
- 2.9.5
+ 2.13.3
true
com.fasterxml.jackson.core
jackson-databind
- 2.9.5
+ 2.13.3
true
com.google.code.gson
gson
- 2.8.3
+ 2.9.1
true
org.openjdk.jmh
jmh-core
- 1.20
+ 1.35
test
org.openjdk.jmh
jmh-generator-annprocess
- 1.20
+ 1.35
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
test
@@ -119,17 +125,18 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.7.0
+ 3.10.1
-
- 1.6
+ 17
+
+ 17
UTF-8
org.apache.maven.plugins
maven-source-plugin
- 3.0.1
+ 3.2.1
attach-sources
@@ -142,7 +149,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.0.0
+ 3.4.0
attach-javadocs
@@ -150,7 +157,7 @@
jar
- -Xdoclint:none
+ none
@@ -172,7 +179,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.8
+ 1.6.13
true
ossrh
@@ -194,8 +201,9 @@
org.apache.maven.plugins
maven-surefire-plugin
- 2.21.0
+ 2.20
+ true
methods
1
false
@@ -209,6 +217,46 @@
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.11.0
+
+ file:///${project.basedir}/DependencyUpdateSearch_Rules.xml
+
+
+
+ verify
+
+ display-dependency-updates
+ display-plugin-updates
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+ 3.1.0
+
+
+ enforce-maven
+
+ enforce
+
+
+
+
+ [3.3.2,)
+
+
+
+
+
+
+
diff --git a/src/main/java/com/jsoniter/ReflectionDecoderFactory.java b/src/main/java/com/jsoniter/ReflectionDecoderFactory.java
index 65dee380..2aaebc1d 100644
--- a/src/main/java/com/jsoniter/ReflectionDecoderFactory.java
+++ b/src/main/java/com/jsoniter/ReflectionDecoderFactory.java
@@ -23,6 +23,9 @@ public static Decoder create(ClassInfo classAndArgs) {
if (clazz.isEnum()) {
return new ReflectionEnumDecoder(clazz);
}
+ if (clazz.isRecord()) {
+ return new ReflectionRecordDecoder(classAndArgs).create();
+ }
return new ReflectionObjectDecoder(classAndArgs).create();
}
}
diff --git a/src/main/java/com/jsoniter/ReflectionObjectDecoder.java b/src/main/java/com/jsoniter/ReflectionObjectDecoder.java
index e1e76f73..2297b719 100644
--- a/src/main/java/com/jsoniter/ReflectionObjectDecoder.java
+++ b/src/main/java/com/jsoniter/ReflectionObjectDecoder.java
@@ -9,20 +9,20 @@
class ReflectionObjectDecoder {
- private static Object NOT_SET = new Object() {
+ protected static Object NOT_SET = new Object() {
@Override
public String toString() {
return "NOT_SET";
}
};
- private Map allBindings = new HashMap();
- private String tempCacheKey;
- private String ctorArgsCacheKey;
- private int tempCount;
- private long expectedTracker;
- private int requiredIdx;
- private int tempIdx;
- private ClassDescriptor desc;
+ protected Map allBindings = new HashMap();
+ protected String tempCacheKey;
+ protected String ctorArgsCacheKey;
+ protected int tempCount;
+ protected long expectedTracker;
+ protected int requiredIdx;
+ protected int tempIdx;
+ protected ClassDescriptor desc;
public ReflectionObjectDecoder(ClassInfo classInfo) {
try {
@@ -34,7 +34,8 @@ public ReflectionObjectDecoder(ClassInfo classInfo) {
}
}
- private final void init(ClassInfo classInfo) throws Exception {
+ protected final void init(ClassInfo classInfo) throws Exception {
+
Class clazz = classInfo.clazz;
ClassDescriptor desc = ClassDescriptor.getDecodingClassDescriptor(classInfo, true);
for (Binding param : desc.ctor.parameters) {
@@ -346,7 +347,7 @@ private void setToBinding(Object obj, Binding binding, Object value) throws Exce
}
}
- private void setExtra(Object obj, Map extra) throws Exception {
+ protected void setExtra(Object obj, Map extra) throws Exception {
if (extra == null) {
return;
}
@@ -367,24 +368,24 @@ private void setExtra(Object obj, Map extra) throws Exception {
}
}
- private boolean canNotSetDirectly(Binding binding) {
+ protected boolean canNotSetDirectly(Binding binding) {
return binding.field == null && binding.method == null;
}
- private Object decodeBinding(JsonIterator iter, Binding binding) throws Exception {
+ protected Object decodeBinding(JsonIterator iter, Binding binding) throws Exception {
Object value;
value = binding.decoder.decode(iter);
return value;
}
- private Object decodeBinding(JsonIterator iter, Object obj, Binding binding) throws Exception {
+ protected Object decodeBinding(JsonIterator iter, Object obj, Binding binding) throws Exception {
if (binding.valueCanReuse) {
CodegenAccess.setExistingObject(iter, binding.field.get(obj));
}
return decodeBinding(iter, binding);
}
- private Map onUnknownProperty(JsonIterator iter, Slice fieldName, Map extra) throws IOException {
+ protected Map onUnknownProperty(JsonIterator iter, Slice fieldName, Map extra) throws IOException {
boolean shouldReadValue = desc.asExtraForUnknownProperties || !desc.keyValueTypeWrappers.isEmpty();
if (shouldReadValue) {
Any value = iter.readAny();
@@ -398,7 +399,7 @@ private Map onUnknownProperty(JsonIterator iter, Slice fieldName
return extra;
}
- private List collectMissingFields(long tracker) {
+ protected List collectMissingFields(long tracker) {
List missingFields = new ArrayList();
for (Binding binding : allBindings.values()) {
if (binding.asMissingWhenNotPresent) {
@@ -409,7 +410,7 @@ private List collectMissingFields(long tracker) {
return missingFields;
}
- private void applyWrappers(Object[] temp, Object obj) throws Exception {
+ protected void applyWrappers(Object[] temp, Object obj) throws Exception {
for (WrapperDescriptor wrapper : desc.bindingTypeWrappers) {
Object[] args = new Object[wrapper.parameters.size()];
for (int i = 0; i < wrapper.parameters.size(); i++) {
@@ -422,7 +423,7 @@ private void applyWrappers(Object[] temp, Object obj) throws Exception {
}
}
- private Object createNewObject(JsonIterator iter, Object[] temp) throws Exception {
+ protected Object createNewObject(JsonIterator iter, Object[] temp) throws Exception {
if (iter.tempObjects == null) {
iter.tempObjects = new HashMap();
}
diff --git a/src/main/java/com/jsoniter/ReflectionRecordDecoder.java b/src/main/java/com/jsoniter/ReflectionRecordDecoder.java
new file mode 100644
index 00000000..9c71717a
--- /dev/null
+++ b/src/main/java/com/jsoniter/ReflectionRecordDecoder.java
@@ -0,0 +1,113 @@
+package com.jsoniter;
+
+import com.jsoniter.spi.*;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReflectionRecordDecoder extends ReflectionObjectDecoder {
+
+ private boolean useOnlyFieldRecord = false;
+
+ public ReflectionRecordDecoder(ClassInfo classInfo) {
+
+ super(classInfo);
+
+ if (desc.clazz.isRecord() && !desc.fields.isEmpty() && tempCount == 0) {
+ tempCount = tempIdx;
+ tempCacheKey = "temp@" + desc.clazz.getName();
+ ctorArgsCacheKey = "ctor@" + desc.clazz.getName();
+
+ desc.ctor.parameters.addAll(desc.fields);
+ useOnlyFieldRecord = true;
+ }
+ }
+
+ @Override
+ public Decoder create() {
+
+ if (useOnlyFieldRecord)
+ return new OnlyFieldRecord();
+
+ if (desc.ctor.parameters.isEmpty()) {
+ if (desc.bindingTypeWrappers.isEmpty()) {
+ return new OnlyFieldRecord();
+ } else {
+ return new WithWrapper();
+ }
+ } else {
+ return new WithCtor();
+ }
+ }
+
+ public class OnlyFieldRecord implements Decoder {
+
+ @Override
+ public Object decode(JsonIterator iter) throws IOException {
+
+ try {
+ return decode_(iter);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new JsonException(e);
+ }
+ }
+
+ private Object decode_(JsonIterator iter) throws Exception {
+ if (iter.readNull()) {
+ CodegenAccess.resetExistingObject(iter);
+ return null;
+ }
+ if (iter.tempObjects == null) {
+ iter.tempObjects = new HashMap();
+ }
+ Object[] temp = (Object[]) iter.tempObjects.get(tempCacheKey);
+ if (temp == null) {
+ temp = new Object[tempCount];
+ iter.tempObjects.put(tempCacheKey, temp);
+ }
+ Arrays.fill(temp, NOT_SET);
+ if (!CodegenAccess.readObjectStart(iter)) {
+ if (requiredIdx > 0) {
+ throw new JsonException("missing required properties: " + collectMissingFields(0));
+ }
+ return createNewObject(iter, temp);
+ }
+ Map extra = null;
+ long tracker = 0L;
+ Slice fieldName = CodegenAccess.readObjectFieldAsSlice(iter);
+ Binding binding = allBindings.get(fieldName);
+ if (binding == null) {
+ extra = onUnknownProperty(iter, fieldName, extra);
+ } else {
+ if (binding.asMissingWhenNotPresent) {
+ tracker |= binding.mask;
+ }
+ temp[binding.idx] = decodeBinding(iter, binding);
+ }
+ while (CodegenAccess.nextToken(iter) == ',') {
+ fieldName = CodegenAccess.readObjectFieldAsSlice(iter);
+ binding = allBindings.get(fieldName);
+ if (binding == null) {
+ extra = onUnknownProperty(iter, fieldName, extra);
+ } else {
+ if (binding.asMissingWhenNotPresent) {
+ tracker |= binding.mask;
+ }
+ temp[binding.idx] = decodeBinding(iter, binding);
+ }
+ }
+ if (tracker != expectedTracker) {
+ throw new JsonException("missing required properties: " + collectMissingFields(tracker));
+ }
+ Object obj = createNewObject(iter, temp.clone());
+ setExtra(obj, extra);
+ applyWrappers(temp, obj);
+ return obj;
+ }
+
+ }
+}
diff --git a/src/main/java/com/jsoniter/spi/ClassDescriptor.java b/src/main/java/com/jsoniter/spi/ClassDescriptor.java
index a47dbe5d..1cd43195 100644
--- a/src/main/java/com/jsoniter/spi/ClassDescriptor.java
+++ b/src/main/java/com/jsoniter/spi/ClassDescriptor.java
@@ -31,7 +31,7 @@ public static ClassDescriptor getDecodingClassDescriptor(ClassInfo classInfo, bo
desc.classInfo = classInfo;
desc.clazz = clazz;
desc.lookup = lookup;
- desc.ctor = getCtor(clazz);
+ desc.ctor = clazz.isRecord() ? getRecordCtor(clazz) : getCtor(clazz);
desc.setters = getSetters(lookup, classInfo, includingPrivate);
desc.getters = new ArrayList();
desc.fields = getFields(lookup, classInfo, includingPrivate);
@@ -203,6 +203,17 @@ private static ConstructorDescriptor getCtor(Class clazz) {
return cctor;
}
+ private static ConstructorDescriptor getRecordCtor(Class> clazz) {
+ ConstructorDescriptor cctor = new ConstructorDescriptor();
+ try {
+ Class>[] canonicalParameterTypes = Arrays.stream(clazz.getRecordComponents()).map(RecordComponent::getType).toArray(Class>[]::new);
+ cctor.ctor = clazz.getDeclaredConstructor(canonicalParameterTypes);
+ } catch (Exception e) {
+ cctor.ctor = null;
+ }
+ return cctor;
+ }
+
private static List getFields(Map lookup, ClassInfo classInfo, boolean includingPrivate) {
ArrayList bindings = new ArrayList();
for (Field field : getAllFields(classInfo.clazz)) {
@@ -432,7 +443,6 @@ public List allDecoderBindings() {
return bindings;
}
-
public List allEncoderBindings() {
ArrayList bindings = new ArrayList(8);
bindings.addAll(fields);
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
new file mode 100644
index 00000000..57b5d2c8
--- /dev/null
+++ b/src/main/java/module-info.java
@@ -0,0 +1,38 @@
+open module com.jsoniter {
+
+ exports com.jsoniter;
+
+ exports com.jsoniter.fuzzy;
+
+ exports com.jsoniter.static_codegen;
+
+ exports com.jsoniter.extra;
+
+ exports com.jsoniter.output;
+
+ exports com.jsoniter.annotation;
+
+ exports com.jsoniter.spi;
+
+ exports com.jsoniter.any;
+
+
+ /** static, because marked as optional in pom.xml*/
+ requires static javassist;
+
+ /** static, because marked as optional in pom.xml*/
+ requires static com.fasterxml.jackson.core;
+
+ /** static, because marked as optional in pom.xml*/
+ requires static com.fasterxml.jackson.annotation;
+
+ /** static, because marked as optional in pom.xml*/
+ requires static com.fasterxml.jackson.databind;
+
+ /** static, because marked as optional in pom.xml*/
+ requires static com.google.gson;
+
+ /** static, because only used in testing */
+ requires static java.desktop;
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/jsoniter/IterImplForStreamingTest.java b/src/test/java/com/jsoniter/IterImplForStreamingTest.java
index e0432d39..a66802d4 100644
--- a/src/test/java/com/jsoniter/IterImplForStreamingTest.java
+++ b/src/test/java/com/jsoniter/IterImplForStreamingTest.java
@@ -6,8 +6,8 @@
import java.io.IOException;
import java.io.InputStream;
import junit.framework.TestCase;
+import org.apache.commons.lang3.NotImplementedException;
import org.junit.experimental.categories.Category;
-import sun.reflect.generics.reflectiveObjects.NotImplementedException;
public class IterImplForStreamingTest extends TestCase {
@@ -77,7 +77,7 @@ private static InputStream getSluggishInputStream(final byte[] src) {
@Override
public int read() throws IOException {
- throw new NotImplementedException();
+ throw new NotImplementedException(new Exception());
}
@Override
diff --git a/src/test/java/com/jsoniter/SimpleRecord.java b/src/test/java/com/jsoniter/SimpleRecord.java
new file mode 100644
index 00000000..7a740468
--- /dev/null
+++ b/src/test/java/com/jsoniter/SimpleRecord.java
@@ -0,0 +1,11 @@
+package com.jsoniter;
+
+public record SimpleRecord(String field1, String field2) {
+ public SimpleRecord() {
+ this(null, null);
+ }
+ public SimpleRecord(String field1, String field2) {
+ this.field1 = field1;
+ this.field2 = field2;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/jsoniter/TestRecord.java b/src/test/java/com/jsoniter/TestRecord.java
new file mode 100644
index 00000000..423ac810
--- /dev/null
+++ b/src/test/java/com/jsoniter/TestRecord.java
@@ -0,0 +1,258 @@
+package com.jsoniter;
+
+
+import com.jsoniter.annotation.JsonCreator;
+import com.jsoniter.annotation.JsonProperty;
+import com.jsoniter.any.Any;
+import com.jsoniter.spi.ClassDescriptor;
+import com.jsoniter.spi.ClassInfo;
+import com.jsoniter.spi.JsonException;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+public class TestRecord extends TestCase {
+
+ record TestRecord1(long field1) {
+ }
+
+ public record TestRecord0(Long id, String name) {
+
+ public TestRecord0() {
+
+ this(0L, "");
+ }
+ }
+
+ // remove "disabled" to run the function
+ public void disabled_test_print_record_reflection_info() {
+
+ Class clazz = TestRecord1.class;
+
+ System.out.println("Record Constructors :");
+ for (Constructor> constructor : clazz.getConstructors()) {
+ System.out.println(constructor);
+ }
+
+ System.out.println("Record Methods : ");
+ for (Method method : clazz.getMethods()) {
+ System.out.println(method);
+ }
+
+ System.out.println("Record Fields : ");
+ for (Field field : clazz.getFields()) {
+ System.out.println(field);
+ System.out.println(" modifiers : " + Modifier.toString(field.getModifiers()));
+ }
+
+ System.out.println("Record Declared Fields : ");
+ for (Field field : clazz.getDeclaredFields()) {
+ System.out.println(field);
+ System.out.println(" modifiers : " + Modifier.toString(field.getModifiers()));
+ }
+
+ try {
+ System.out.println("Record Default Declared Constructor : " + clazz.getDeclaredConstructor());
+ } catch (Exception ex) {
+ System.err.println("No Record Default Declared Constructor!");
+ }
+
+ System.out.println("Record Declared Constructors : ");
+ for (Constructor> constructor : clazz.getDeclaredConstructors()) {
+ System.out.println(constructor);
+ System.out.println(" name : " + constructor.getName());
+ System.out.println(" modifiers : " + Modifier.toString(constructor.getModifiers()));
+ System.out.println(" input count : " + constructor.getParameterCount());
+ System.out.println(" input types : ");
+ for (Class> parameter : constructor.getParameterTypes())
+ System.out.println(" " + parameter);
+ }
+ }
+
+ public void test_empty_record() throws IOException {
+
+ JsonIterator iter = JsonIterator.parse("{}");
+ assertNotNull(iter.read(TestRecord0.class));
+ }
+
+ public void test_empty_simple_record() throws IOException {
+
+ JsonIterator iter = JsonIterator.parse("{}");
+ SimpleRecord simpleRecord = iter.read(SimpleRecord.class);
+ assertNull(simpleRecord.field1());
+ iter.reset(iter.buf);
+ Object obj = iter.read(Object.class);
+ assertEquals(0, ((Map) obj).size());
+ iter.reset(iter.buf);
+ Any any = iter.readAny();
+ assertEquals(0, any.size());
+ }
+
+ public void test_record_error() throws IOException {
+
+ JsonIterator iter = JsonIterator.parse("{ 'field1' : 1 }".replace('\'', '"'));
+ try {
+ TestRecord1 rec = iter.read(TestRecord1.class);
+ assertEquals(1, rec.field1);
+ } catch (JsonException e) {
+ throw new JsonException("no constructor for: class com.jsoniter.TestRecord", e);
+ }
+ }
+
+ public void test_record_withOnlyFieldDecoder() throws IOException {
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord1.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'field1' : 1 }".replace('\'', '"'));
+ TestRecord1 record = iter.read(TestRecord1.class);
+
+ assertEquals(1, record.field1);
+ }
+
+ public void test_record_2_fields_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecord2(long field1, String field2) {
+ }
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord2.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'field1' : 1, 'field2' : 'hey' }".replace('\'', '"'));
+ TestRecord2 record = iter.read(TestRecord2.class);
+
+ assertEquals(1, record.field1);
+ assertEquals("hey", record.field2);
+ }
+
+ public void test_record_2_fields_swapFieldOrder_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecord2(String field2, long field1) {
+ }
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord2.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'field2' : 'hey', 'field1' : 1 }".replace('\'', '"'));
+ TestRecord2 record = iter.read(TestRecord2.class);
+
+ assertEquals(1, record.field1);
+ assertEquals("hey", record.field2);
+ }
+
+ public void test_record_recordComposition_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecordA(long fieldA) {
+ }
+ record TestRecordB(long fieldB, TestRecordA a) {
+ }
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecordB.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'fieldB' : 1, 'a' : { 'fieldA' : 69 } }".replace('\'', '"'));
+ TestRecordB record = iter.read(TestRecordB.class);
+
+ assertEquals(1, record.fieldB);
+ assertEquals(69, record.a.fieldA);
+ }
+
+ public void test_record_empty_constructor_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecord3() {
+ }
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord3.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'fieldB' : 1, 'a' : { 'fieldA' : 69 } }".replace('\'', '"'));
+ TestRecord3 record = iter.read(TestRecord3.class);
+
+ assertNotNull(record);
+ }
+
+ public void test_enum() throws IOException {
+
+ record TestRecord5(MyEnum field1) {
+
+ enum MyEnum {
+ HELLO,
+ WOW
+ }
+ }
+
+ TestRecord5 obj = JsonIterator.deserialize("{\"field1\":\"HELLO\"}", TestRecord5.class);
+ assertEquals(TestRecord5.MyEnum.HELLO, obj.field1);
+ try {
+ JsonIterator.deserialize("{\"field1\":\"HELLO1\"}", TestRecord5.class);
+ fail();
+ } catch (JsonException e) {
+ }
+ obj = JsonIterator.deserialize("{\"field1\":null}", TestRecord5.class);
+ assertNull(obj.field1);
+ obj = JsonIterator.deserialize("{\"field1\":\"WOW\"}", TestRecord5.class);
+ assertEquals(TestRecord5.MyEnum.WOW, obj.field1);
+ }
+
+ public void test_record_2_constructors_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecord6(long val) {
+
+ public TestRecord6(int valInt) {
+
+ this(Long.valueOf(valInt));
+ }
+ }
+
+ assertEquals(ReflectionRecordDecoder.OnlyFieldRecord.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord6.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'val' : 1 }".replace('\'', '"'));
+ TestRecord6 record = iter.read(TestRecord6.class);
+
+ assertNotNull(record);
+ }
+
+ public void test_record_2_constructors_secondCtorUse_withOnlyFieldDecoder() throws IOException {
+
+ record TestRecord6(long val) {
+
+ @JsonCreator
+ public TestRecord6(@JsonProperty("valInt") int valInt) {
+
+ this(Long.valueOf(valInt));
+ }
+ }
+
+ assertEquals(ReflectionRecordDecoder.WithCtor.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord6.class)).getClass());
+
+ JsonIterator iter = JsonIterator.parse("{ 'valInt' : 1 }".replace('\'', '"'));
+ TestRecord6 record = iter.read(TestRecord6.class);
+
+ assertNotNull(record);
+ }
+
+ public void test_record_withCtorDecoder() throws IOException {
+
+ record TestRecord2(@JsonProperty long field1) {
+
+ @JsonCreator
+ TestRecord2 {
+ }
+ }
+ assertEquals(ReflectionRecordDecoder.WithCtor.class, ReflectionDecoderFactory.create(new ClassInfo(TestRecord2.class)).getClass());
+
+ assertEquals(ReflectionDecoderFactory.create(new ClassInfo(TestRecord2.class)).getClass(), ReflectionObjectDecoder.WithCtor.class);
+
+ JsonIterator iter = JsonIterator.parse("{ 'field1' : 1 }".replace('\'', '"'));
+ TestRecord2 record = iter.read(TestRecord2.class);
+
+ assertEquals(1, record.field1);
+ }
+
+ public void test_record_constructor() throws IOException {
+ ClassDescriptor desc = ClassDescriptor.getDecodingClassDescriptor(new ClassInfo(TestRecord0.class), false);
+ assertEquals(TestRecord0.class.getConstructors()[1], desc.ctor.ctor);
+
+ }
+
+}
diff --git a/src/test/java/com/jsoniter/any/TestRecord.java b/src/test/java/com/jsoniter/any/TestRecord.java
new file mode 100644
index 00000000..4631832a
--- /dev/null
+++ b/src/test/java/com/jsoniter/any/TestRecord.java
@@ -0,0 +1,55 @@
+package com.jsoniter.any;
+import junit.framework.TestCase;
+
+import java.util.*;
+
+public class TestRecord extends TestCase {
+
+ record TestRecord1(int field1) {
+
+ }
+
+ public void test_wrap_int(){
+ Any any = Any.wrap(new TestRecord1(3));
+ assertEquals(3, any.get("field1").toInt());
+ }
+
+ record TestRecord2(int field1, String field2) {
+
+ }
+
+ public void test_iterator(){
+ Any any = Any.wrap(new TestRecord2(3,"hej"));
+ Any.EntryIterator iter = any.entries();
+ HashMap map = new HashMap();
+ while (iter.next()) {
+ if(iter.key() == "field1"){
+ assertEquals(3,iter.value().toInt());
+ }
+ if(iter.key() == "field2"){
+ assertEquals("hej",iter.value().toString());
+ }
+ }
+ }
+
+ public void test_size() {
+ Any any = Any.wrap(new TestRecord2(7,"ho"));
+ assertEquals(2, any.size());
+ }
+
+ public void test_to_string() {
+ assertEquals("{\"field1\":7,\"field2\":\"hej\"}", Any.wrap(new TestRecord2(7,"hej")).toString());
+ }
+
+ record TestRecord3(){
+
+ }
+
+ public void test_to_boolean() {
+ Any any = Any.wrap(new TestRecord3());
+ assertFalse(any.toBoolean());
+ any = Any.wrap(new TestRecord2(1,"hallo"));
+ assertTrue(any.toBoolean());
+ }
+
+}
diff --git a/src/test/java/com/jsoniter/output/TestNested.java b/src/test/java/com/jsoniter/output/TestNested.java
index 00fd8d6d..e3750c66 100644
--- a/src/test/java/com/jsoniter/output/TestNested.java
+++ b/src/test/java/com/jsoniter/output/TestNested.java
@@ -1,16 +1,12 @@
package com.jsoniter.output;
+import java.io.*;
+import java.util.*;
+
import com.jsoniter.annotation.JsonProperty;
-import com.jsoniter.spi.JsoniterSpi;
-import com.jsoniter.spi.TypeLiteral;
-import junit.framework.TestCase;
+import com.jsoniter.spi.*;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import junit.framework.TestCase;
public class TestNested extends TestCase {
@@ -45,7 +41,7 @@ public void test_collection_of_objects() throws IOException {
obj1.field1 = "1";
obj1.field2 = "2";
String output = JsonStream.serialize(new TypeLiteral>() {
- }, new ArrayList() {{
+ }, new ArrayList<>() {{
add(obj1);
}});
assertTrue(output.contains("field1"));
@@ -92,7 +88,7 @@ public void test_map_of_objects() throws IOException {
obj1.field1 = "1";
obj1.field2 = "2";
stream.writeVal(new TypeLiteral