Skip to content

Commit b72681d

Browse files
authored
Feature/inherited json identity info (#946)
* Add subclass of `JsonIdentityInfo` class. Represent the current (buggy) state in the unit test. Note: that Jackson treats the subclass as a `JsonIdentityInfo` even though the annotation is not inherited. * Update tests for correct behavior. Subclasses of `JsonIdentityInfo` class should be treated like `JsonIdentityInfo` classes. * Update `Jackson2Parser.java` to handle "inheried" `JsonIdentityInfo`. The parser needs to walk the class hierarchy looking for `JsonIdentityInfo` because the annotation is not marked as `Inherited`, but Jackson observes the `JsonIdentityInfo` behavior on subclasses regardless.
1 parent 63e6a7c commit b72681d

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,20 @@ private static Integer getCreatorIndex(BeanProperty beanProperty) {
365365
}
366366
}
367367

368+
private <T extends Annotation> T findClassAnnotation(Class<?> cls, Class<T> annotation) {
369+
T identityInfo = cls.getAnnotation(annotation);
370+
371+
if (identityInfo == null) {
372+
Class<?> parent = cls.getSuperclass();
373+
374+
if (parent != null) {
375+
return findClassAnnotation(parent, annotation);
376+
}
377+
}
378+
379+
return identityInfo;
380+
}
381+
368382
// @JsonIdentityInfo and @JsonIdentityReference
369383
private Type processIdentity(Type propertyType, BeanProperty beanProperty) {
370384

@@ -373,13 +387,13 @@ private Type processIdentity(Type propertyType, BeanProperty beanProperty) {
373387
final Class<?> cls = clsT != null ? clsT : clsW;
374388

375389
if (cls != null) {
376-
final JsonIdentityInfo identityInfoC = cls.getAnnotation(JsonIdentityInfo.class);
390+
final JsonIdentityInfo identityInfoC = this.findClassAnnotation(cls, JsonIdentityInfo.class);
377391
final JsonIdentityInfo identityInfoP = beanProperty.getAnnotation(JsonIdentityInfo.class);
378392
final JsonIdentityInfo identityInfo = identityInfoP != null ? identityInfoP : identityInfoC;
379393
if (identityInfo == null) {
380394
return null;
381395
}
382-
final JsonIdentityReference identityReferenceC = cls.getAnnotation(JsonIdentityReference.class);
396+
final JsonIdentityReference identityReferenceC = this.findClassAnnotation(cls, JsonIdentityReference.class);
383397
final JsonIdentityReference identityReferenceP = beanProperty.getAnnotation(JsonIdentityReference.class);
384398
final JsonIdentityReference identityReference = identityReferenceP != null ? identityReferenceP : identityReferenceC;
385399
final boolean alwaysAsId = identityReference != null && identityReference.alwaysAsId();

typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ObjectAsIdTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ public class ObjectAsIdTest {
2626
@Test
2727
public void testJackson() throws JsonProcessingException {
2828
final TestObjectA testObjectA = new TestObjectA();
29+
final TestObjectSubA testObjectSubA = new TestObjectSubA();
2930
final TestObjectB testObjectB = new TestObjectB();
3031
final TestObjectC<String> testObjectC = new TestObjectC<>("valueC");
3132
final TestObjectD testObjectD = new TestObjectD();
3233
final TestObjectE testObjectE = new TestObjectE();
3334
final Wrapper wrapper = new Wrapper();
3435
wrapper.testObjectA1 = testObjectA;
3536
wrapper.testObjectA2 = testObjectA;
37+
wrapper.testObjectSubA = testObjectSubA;
3638
wrapper.testObjectB1 = testObjectB;
3739
wrapper.testObjectB2 = testObjectB;
3840
wrapper.testObjectC1 = testObjectC;
@@ -47,6 +49,7 @@ public void testJackson() throws JsonProcessingException {
4749
final String json = objectMapper.writeValueAsString(wrapper);
4850
Assertions.assertTrue(json.contains("\"testObjectA1\": \"id1\""));
4951
Assertions.assertTrue(json.contains("\"testObjectA2\": \"id1\""));
52+
Assertions.assertTrue(json.contains("\"testObjectSubA\": \"id1\""));
5053
Assertions.assertTrue(json.contains("\"testObjectB1\": {"));
5154
Assertions.assertTrue(json.contains("\"testObjectB2\": \"id2\""));
5255
Assertions.assertTrue(json.contains("\"testObjectC1\": {"));
@@ -121,13 +124,15 @@ public void test() {
121124
final Settings settings = TestUtils.settings();
122125
final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(Wrapper.class));
123126
Assertions.assertTrue(output.contains("testObjectA1: string"));
127+
Assertions.assertTrue(output.contains("testObjectSubA: string"));
124128
Assertions.assertTrue(output.contains("testObjectB1: TestObjectB | string"));
125129
Assertions.assertTrue(output.contains("testObjectC1: TestObjectC<string> | string"));
126130
Assertions.assertTrue(output.contains("testObjectD1: string"));
127131
Assertions.assertTrue(output.contains("testObjectE1: string"));
128132
Assertions.assertTrue(output.contains("testObjectE2: TestObjectE | string"));
129133
Assertions.assertTrue(output.contains("testObjectE3: TestObjectE"));
130134
Assertions.assertTrue(!output.contains("interface TestObjectA"));
135+
Assertions.assertTrue(!output.contains("interface TestObjectSubA"));
131136
Assertions.assertTrue(output.contains("interface TestObjectB"));
132137
Assertions.assertTrue(output.contains("interface TestObjectC<T>"));
133138
Assertions.assertTrue(!output.contains("interface TestObjectD"));
@@ -197,6 +202,10 @@ private static class TestObjectA {
197202
public String myProperty = "valueA";
198203
}
199204

205+
private static class TestObjectSubA extends TestObjectA {
206+
public String subProperty = "valueSubA";
207+
}
208+
200209
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "@@@id")
201210
private static class TestObjectB {
202211

@@ -277,6 +286,7 @@ private static class TestObjectE {
277286
private static class Wrapper {
278287
public TestObjectA testObjectA1;
279288
public TestObjectA testObjectA2;
289+
public TestObjectSubA testObjectSubA;
280290
public TestObjectB testObjectB1;
281291
public TestObjectB testObjectB2;
282292
public TestObjectC<String> testObjectC1;

0 commit comments

Comments
 (0)