55import dev .lukebemish .codecextras .structured .CodecInterpreter ;
66import dev .lukebemish .codecextras .structured .Structure ;
77import dev .lukebemish .codecextras .structured .reflective .ReflectiveStructureCreator ;
8+ import dev .lukebemish .codecextras .structured .reflective .annotations .SerializedProperty ;
9+ import dev .lukebemish .codecextras .structured .reflective .annotations .Transient ;
810import dev .lukebemish .codecextras .test .CodecAssertions ;
11+ import java .lang .annotation .Retention ;
12+ import java .lang .annotation .RetentionPolicy ;
913import java .util .LinkedHashSet ;
1014import java .util .List ;
15+ import java .util .Objects ;
1116import java .util .Optional ;
1217import java .util .OptionalInt ;
1318import java .util .SequencedSet ;
1419import org .jspecify .annotations .Nullable ;
1520import org .junit .jupiter .api .Test ;
1621
1722public class TestReflective {
18- public record TestRecord (int a , String b , TestEnum c , OptionalInt d , Optional <String > e , @ Nullable String f , SequencedSet <Integer > g ) {
23+ public record TestRecord (long a , String b , TestEnum c , OptionalInt d , Optional <String > e , @ Nullable String f , SequencedSet <Integer > g ) {
1924 private static final Structure <TestRecord > STRUCTURE = ReflectiveStructureCreator .create (TestRecord .class );
2025 }
2126
@@ -25,6 +30,120 @@ public enum TestEnum {
2530 C
2631 }
2732
33+ public static class TestNoArgCtor {
34+ public int a ;
35+ private @ Nullable String b ;
36+
37+ public @ Nullable String getB () {
38+ return this .b ;
39+ }
40+
41+ public void setB (String b ) {
42+ this .b = b ;
43+ }
44+
45+ @ Override
46+ public boolean equals (Object object ) {
47+ if (this == object ) return true ;
48+ if (!(object instanceof TestNoArgCtor that )) return false ;
49+ return a == that .a && Objects .equals (b , that .b );
50+ }
51+
52+ @ Override
53+ public int hashCode () {
54+ return Objects .hash (a , b );
55+ }
56+
57+ @ Override
58+ public String toString () {
59+ return "TestNoArgCtor{" +
60+ "a=" + a +
61+ ", b='" + b + '\'' +
62+ '}' ;
63+ }
64+ }
65+
66+ public static class TestCtor {
67+ public final int a ;
68+ private final String b ;
69+
70+ public String getB () {
71+ return this .b ;
72+ }
73+
74+ public TestCtor (
75+ @ SerializedProperty ("a" ) int a ,
76+ @ SerializedProperty ("b" ) String b
77+ ) {
78+ this .a = a ;
79+ this .b = b ;
80+ }
81+
82+ @ Override
83+ public boolean equals (Object object ) {
84+ if (this == object ) return true ;
85+ if (!(object instanceof TestCtor testCtor )) return false ;
86+ return a == testCtor .a && Objects .equals (b , testCtor .b );
87+ }
88+
89+ @ Override
90+ public int hashCode () {
91+ return Objects .hash (a , b );
92+ }
93+
94+ @ Override
95+ public String toString () {
96+ return "TestCtor{" +
97+ "a=" + a +
98+ ", b='" + b + '\'' +
99+ '}' ;
100+ }
101+ }
102+
103+ public static class TestAnnotations {
104+ public long a ;
105+ public transient boolean b ;
106+
107+ private boolean c ;
108+ @ Transient
109+ public boolean getC () {
110+ return this .c ;
111+ }
112+ public void setC (boolean c ) {
113+ this .c = c ;
114+ }
115+
116+ private boolean d ;
117+ public boolean isD () {
118+ return this .d ;
119+ }
120+ public void setD (boolean d ) {
121+ this .d = d ;
122+ }
123+
124+ @ Override
125+ public boolean equals (Object object ) {
126+ if (this == object ) return true ;
127+ if (!(object instanceof TestAnnotations that )) return false ;
128+ return a == that .a && b == that .b && c == that .c && d == that .d ;
129+ }
130+
131+ @ Override
132+ public int hashCode () {
133+ return Objects .hash (a , b , c , d );
134+ }
135+
136+ @ Override
137+ public String toString () {
138+ return "TestAnnotations{" +
139+ "a=" + a +
140+ ", b=" + b +
141+ ", c=" + c +
142+ ", d=" + d +
143+ '}' ;
144+ }
145+ }
146+
28147 public record TestRecursive (String name , List <TestRecursive > list ) {}
29148
30149 private static final Codec <TestRecord > CODEC = CodecInterpreter .create ().interpret (TestRecord .STRUCTURE ).getOrThrow ();
@@ -34,6 +153,11 @@ public record TestRecursive(String name, List<TestRecursive> list) {}
34153
35154 private static final Codec <TestRecursive > RECURSIVE_CODEC = CodecInterpreter .create ().interpret (ReflectiveStructureCreator .create (TestRecursive .class )).getOrThrow ();
36155
156+ private static final Codec <TestCtor > CTOR_CODEC = CodecInterpreter .create ().interpret (ReflectiveStructureCreator .create (TestCtor .class )).getOrThrow ();
157+ private static final Codec <TestNoArgCtor > NO_ARG_CTOR_CODEC = CodecInterpreter .create ().interpret (ReflectiveStructureCreator .create (TestNoArgCtor .class )).getOrThrow ();
158+
159+ private static final Codec <TestAnnotations > ANNOTATIONS_CODEC = CodecInterpreter .create ().interpret (ReflectiveStructureCreator .create (TestAnnotations .class )).getOrThrow ();
160+
37161 private final String json = """
38162 {
39163 "a": 1,
@@ -74,11 +198,36 @@ public record TestRecursive(String name, List<TestRecursive> list) {}
74198 ]
75199 }""" ;
76200
201+ private final String ctorJson = """
202+ {
203+ "a": 1,
204+ "b": "test"
205+ }""" ;
206+
207+ private final String annotationsJson = """
208+ {
209+ "a": 1,
210+ "d": true
211+ }""" ;
212+
77213 private final TestRecord object = new TestRecord (1 , "test" , TestEnum .A , OptionalInt .of (2 ), Optional .of ("test" ), null , new LinkedHashSet <>(List .of (1 , 2 , 3 )));
78214 private final TestRecord [] array = new TestRecord [] { object };
79215 private final int [] primitiveArray = new int [] { 1 , 2 , 3 };
80216 private final TestRecursive recursive = new TestRecursive ("test1" , List .of (new TestRecursive ("test2" , List .of ()), new TestRecursive ("test3" , List .of ())));
81217
218+ private final TestNoArgCtor noArgCtor = new TestNoArgCtor ();
219+ {
220+ noArgCtor .a = 1 ;
221+ noArgCtor .setB ("test" );
222+ }
223+ private final TestCtor ctor = new TestCtor (1 , "test" );
224+
225+ private final TestAnnotations annotations = new TestAnnotations ();
226+ {
227+ annotations .a = 1 ;
228+ annotations .setD (true );
229+ }
230+
82231 @ Test
83232 void testDecoding () {
84233 CodecAssertions .assertDecodes (JsonOps .INSTANCE , json , object , CODEC );
@@ -118,4 +267,83 @@ void testDecodingRecursive() {
118267 void testEncodingRecursive () {
119268 CodecAssertions .assertEncodes (JsonOps .INSTANCE , recursive , recursiveJson , RECURSIVE_CODEC );
120269 }
270+
271+ @ Test
272+ void testDecodingCtor () {
273+ CodecAssertions .assertDecodes (JsonOps .INSTANCE , ctorJson , ctor , CTOR_CODEC );
274+ }
275+
276+ @ Test
277+ void testEncodingCtor () {
278+ CodecAssertions .assertEncodes (JsonOps .INSTANCE , ctor , ctorJson , CTOR_CODEC );
279+ }
280+
281+ @ Test
282+ void testDecodingNoArgCtor () {
283+ CodecAssertions .assertDecodes (JsonOps .INSTANCE , ctorJson , noArgCtor , NO_ARG_CTOR_CODEC );
284+ }
285+
286+ @ Test
287+ void testEncodingNoArgCtor () {
288+ CodecAssertions .assertEncodes (JsonOps .INSTANCE , noArgCtor , ctorJson , NO_ARG_CTOR_CODEC );
289+ }
290+
291+ @ Test
292+ void testDecodingAnnotations () {
293+ CodecAssertions .assertDecodes (JsonOps .INSTANCE , annotationsJson , annotations , ANNOTATIONS_CODEC );
294+ }
295+
296+ @ Test
297+ void testEncodingAnnotations () {
298+ CodecAssertions .assertEncodes (JsonOps .INSTANCE , annotations , annotationsJson , ANNOTATIONS_CODEC );
299+ }
300+
301+ @ Retention (RetentionPolicy .RUNTIME )
302+ public @interface TestAnnotation {
303+ String a ();
304+ long b ();
305+ String [] c ();
306+ long [] d ();
307+ Nested e ();
308+ Nested [] f ();
309+
310+ @interface Nested {
311+ long a ();
312+ }
313+ }
314+ private final String testAnnotationJson = """
315+ {
316+ "a": "test",
317+ "b": 1,
318+ "c": ["test1", "test2"],
319+ "d": [1, 2],
320+ "e": {"a": 1},
321+ "f": [{"a": 1}, {"a": 2}]
322+ }""" ;
323+ private final TestAnnotation testAnnotation = new Object () {
324+ @ TestAnnotation (
325+ a = "test" ,
326+ b = 1 ,
327+ c = {"test1" , "test2" },
328+ d = {1 , 2 },
329+ e = @ TestAnnotation .Nested (a = 1 ),
330+ f = {@ TestAnnotation .Nested (a = 1 ), @ TestAnnotation .Nested (a = 2 )}
331+ )
332+ static class Source {
333+
334+ }
335+
336+ final TestAnnotation annotation = Objects .requireNonNull (Source .class .getAnnotation (TestAnnotation .class ));
337+ }.annotation ;
338+ private static final Codec <TestAnnotation > TEST_ANNOTATION_CODEC = CodecInterpreter .create ().interpret (ReflectiveStructureCreator .create (TestAnnotation .class )).getOrThrow ();
339+
340+ @ Test
341+ void testDecodingTestAnnotation () {
342+ CodecAssertions .assertDecodes (JsonOps .INSTANCE , testAnnotationJson , testAnnotation , TEST_ANNOTATION_CODEC );
343+ }
344+
345+ @ Test
346+ void testEncodingTestAnnotation () {
347+ CodecAssertions .assertEncodes (JsonOps .INSTANCE , testAnnotation , testAnnotationJson , TEST_ANNOTATION_CODEC );
348+ }
121349}
0 commit comments