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 - 1.6 + 17 + 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>() { - }, new HashMap() {{ + }, new HashMap<>() {{ put("hello", obj1); }}); stream.close(); diff --git a/src/test/java/com/jsoniter/output/TestRecord.java b/src/test/java/com/jsoniter/output/TestRecord.java new file mode 100644 index 00000000..8a63edde --- /dev/null +++ b/src/test/java/com/jsoniter/output/TestRecord.java @@ -0,0 +1,39 @@ +package com.jsoniter.output; + +import junit.framework.TestCase; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.*; + +public class TestRecord extends TestCase { + private ByteArrayOutputStream baos; + private JsonStream stream; + + public void setUp() { + baos = new ByteArrayOutputStream(); + stream = new JsonStream(baos, 4096); + } + + record TestRecord1(float field1){ + + } + + public void test_gen_record() throws IOException { + stream.writeVal(new TestRecord1(2.5f)); + stream.close(); + assertEquals("{'field1':2.5}".replace('\'', '"'), baos.toString()); + } + + record TestRecord2(){ + + } + + public void test_empty_record() throws IOException { + stream.writeVal(new TestRecord2()); + stream.close(); + assertEquals("{}".replace('\'', '"'), baos.toString()); + } + + + +} diff --git a/src/test/java/com/jsoniter/suite/AllTestCases.java b/src/test/java/com/jsoniter/suite/AllTestCases.java index d3196ed4..b5054ecf 100644 --- a/src/test/java/com/jsoniter/suite/AllTestCases.java +++ b/src/test/java/com/jsoniter/suite/AllTestCases.java @@ -6,6 +6,7 @@ import com.jsoniter.TestGson; import com.jsoniter.TestNested; import com.jsoniter.TestObject; +import com.jsoniter.TestRecord; import com.jsoniter.TestString; import com.jsoniter.any.TestList; import com.jsoniter.any.TestLong; @@ -58,6 +59,10 @@ TestList.class, TestAnnotationJsonObject.class, TestLong.class, - TestOmitValue.class}) + TestOmitValue.class, + TestRecord.class, + com.jsoniter.output.TestRecord.class, + com.jsoniter.any.TestRecord.class +}) public abstract class AllTestCases { }