33
44import com .fasterxml .jackson .annotation .JsonAutoDetect ;
55import com .fasterxml .jackson .annotation .JsonFormat ;
6+ import com .fasterxml .jackson .annotation .JsonIdentityInfo ;
7+ import com .fasterxml .jackson .annotation .JsonIdentityReference ;
68import com .fasterxml .jackson .annotation .JsonProperty ;
79import com .fasterxml .jackson .annotation .JsonSubTypes ;
810import com .fasterxml .jackson .annotation .JsonTypeInfo ;
911import com .fasterxml .jackson .annotation .JsonTypeName ;
1012import com .fasterxml .jackson .annotation .JsonUnwrapped ;
1113import com .fasterxml .jackson .annotation .JsonValue ;
14+ import com .fasterxml .jackson .annotation .ObjectIdGenerators ;
1215import com .fasterxml .jackson .annotation .PropertyAccessor ;
1316import com .fasterxml .jackson .databind .AnnotationIntrospector ;
1417import com .fasterxml .jackson .databind .BeanDescription ;
3235import cz .habarta .typescript .generator .compiler .EnumKind ;
3336import cz .habarta .typescript .generator .compiler .EnumMemberModel ;
3437import cz .habarta .typescript .generator .util .Predicate ;
38+ import cz .habarta .typescript .generator .util .UnionType ;
3539import cz .habarta .typescript .generator .util .Utils ;
3640import java .beans .BeanInfo ;
3741import java .beans .Introspector ;
4650import java .util .Arrays ;
4751import java .util .List ;
4852import java .util .Map ;
53+ import java .util .Optional ;
4954import java .util .stream .Collectors ;
55+ import java .util .stream .Stream ;
5056
5157
5258public class Jackson2Parser extends ModelParser {
@@ -120,6 +126,7 @@ private BeanModel parseBean(SourceType<Class<?>> sourceClass) {
120126 checkMember (propertyMember , beanPropertyWriter .getName (), sourceClass .type );
121127 Type propertyType = getGenericType (propertyMember );
122128
129+ // Map.Entry
123130 final Class <?> propertyRawClass = Utils .getRawClassOrNull (propertyType );
124131 if (propertyRawClass != null && Map .Entry .class .isAssignableFrom (propertyRawClass )) {
125132 final BeanDescription propertyDescription = objectMapper .getSerializationConfig ().introspect (beanPropertyWriter .getType ());
@@ -130,6 +137,9 @@ private BeanModel parseBean(SourceType<Class<?>> sourceClass) {
130137 propertyType = Utils .replaceRawClassInType (propertyType , Map .class );
131138 }
132139 }
140+
141+ // @JsonIdentityInfo and @JsonIdentityReference
142+ propertyType = processIdentity (propertyType );
133143
134144 if (!isAnnotatedPropertyIncluded (beanPropertyWriter ::getAnnotation , sourceClass .type .getName () + "." + beanPropertyWriter .getName ())) {
135145 continue ;
@@ -191,6 +201,49 @@ private BeanModel parseBean(SourceType<Class<?>> sourceClass) {
191201 return new BeanModel (sourceClass .type , superclass , taggedUnionClasses , discriminantProperty , discriminantLiteral , interfaces , properties , null );
192202 }
193203
204+ private Type processIdentity (Type propertyType ) {
205+ final Class <?> cls = Utils .getRawClassOrNull (propertyType );
206+ if (cls != null ) {
207+ final JsonIdentityInfo identityInfo = cls .getAnnotation (JsonIdentityInfo .class );
208+ if (identityInfo == null ) {
209+ return propertyType ;
210+ }
211+ final JsonIdentityReference identityReference = cls .getAnnotation (JsonIdentityReference .class );
212+ final boolean alwaysAsId = identityReference != null && identityReference .alwaysAsId ();
213+
214+ final Type idType ;
215+ if (identityInfo .generator () == ObjectIdGenerators .None .class ) {
216+ return propertyType ;
217+ } else if (identityInfo .generator () == ObjectIdGenerators .PropertyGenerator .class ) {
218+ final BeanPropertyWriter [] properties = getBeanHelper (cls ).getProperties ();
219+ final Optional <BeanPropertyWriter > property = Stream .of (properties )
220+ .filter (p -> p .getName ().equals (identityInfo .property ()))
221+ .findFirst ();
222+ if (property .isPresent ()) {
223+ final BeanPropertyWriter beanPropertyWriter = property .get ();
224+ final Member propertyMember = beanPropertyWriter .getMember ().getMember ();
225+ checkMember (propertyMember , beanPropertyWriter .getName (), cls );
226+ idType = getGenericType (propertyMember );
227+ } else {
228+ return propertyType ;
229+ }
230+ } else if (identityInfo .generator () == ObjectIdGenerators .IntSequenceGenerator .class ) {
231+ idType = Integer .class ;
232+ } else if (identityInfo .generator () == ObjectIdGenerators .UUIDGenerator .class ) {
233+ idType = String .class ;
234+ } else if (identityInfo .generator () == ObjectIdGenerators .StringIdGenerator .class ) {
235+ idType = String .class ;
236+ } else {
237+ idType = Object .class ;
238+ }
239+ return alwaysAsId
240+ ? idType
241+ : new UnionType (propertyType , idType );
242+
243+ }
244+ return propertyType ;
245+ }
246+
194247 private static Type getGenericType (Member member ) {
195248 if (member instanceof Method ) {
196249 return ((Method ) member ).getGenericReturnType ();
@@ -378,7 +431,7 @@ private DeclarationModel parseEnumOrObjectEnum(SourceType<Class<?>> sourceClass)
378431 return new EnumModel (sourceClass .type , isNumberBased ? EnumKind .NumberBased : EnumKind .StringBased , enumMembers , null );
379432 }
380433
381- private Number getNumberEnumValue (Field field , Method valueMethod , int index ) throws Exception {
434+ private static Number getNumberEnumValue (Field field , Method valueMethod , int index ) throws Exception {
382435 if (valueMethod != null ) {
383436 final Object valueObject = invokeJsonValueMethod (field , valueMethod );
384437 if (valueObject instanceof Number ) {
@@ -388,7 +441,7 @@ private Number getNumberEnumValue(Field field, Method valueMethod, int index) th
388441 return index ;
389442 }
390443
391- private Object getMethodEnumValue (Field field , Method valueMethod ) throws Exception {
444+ private static Object getMethodEnumValue (Field field , Method valueMethod ) throws Exception {
392445 if (valueMethod != null ) {
393446 final Object valueObject = invokeJsonValueMethod (field , valueMethod );
394447 if (valueObject instanceof String || valueObject instanceof Number ) {
@@ -404,15 +457,15 @@ private Object getMethodEnumValue(Field field, Method valueMethod) throws Except
404457 return field .getName ();
405458 }
406459
407- private Object invokeJsonValueMethod (Field field , Method valueMethod ) throws ReflectiveOperationException {
460+ private static Object invokeJsonValueMethod (Field field , Method valueMethod ) throws ReflectiveOperationException {
408461 field .setAccessible (true );
409462 final Object constant = field .get (null );
410463 valueMethod .setAccessible (true );
411464 final Object valueObject = valueMethod .invoke (constant );
412465 return valueObject ;
413466 }
414467
415- private Object getFieldJsonValue (Field field , Field jsonValueField ) throws ReflectiveOperationException {
468+ private static Object getFieldJsonValue (Field field , Field jsonValueField ) throws ReflectiveOperationException {
416469 field .setAccessible (true );
417470 final Object constant = field .get (null );
418471 jsonValueField .setAccessible (true );
0 commit comments