package cz.habarta.typescript.generator.parser; import cz.habarta.typescript.generator.*; import java.lang.annotation.Annotation; import java.lang.reflect.Member; import java.lang.reflect.Type; import java.util.*; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.annotate.JsonSubTypes; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.introspect.NopAnnotationIntrospector; import org.codehaus.jackson.map.ser.*; import org.codehaus.jackson.type.JavaType; public class Jackson1Parser extends ModelParser { private final ObjectMapper objectMapper = new ObjectMapper(); public Jackson1Parser(Settings settings, TypeProcessor typeProcessor) { super(settings, typeProcessor); if (!settings.optionalAnnotations.isEmpty()) { final AnnotationIntrospector defaultAnnotationIntrospector = objectMapper.getSerializationConfig().getAnnotationIntrospector(); final AnnotationIntrospector allAnnotationIntrospector = new NopAnnotationIntrospector() { @Override public boolean isHandled(Annotation ann) { return true; } }; this.objectMapper.setAnnotationIntrospector(new AnnotationIntrospector.Pair(defaultAnnotationIntrospector, allAnnotationIntrospector)); } } @Override protected DeclarationModel parseClass(SourceType<Class<?>> sourceClass) { if (sourceClass.type.isEnum()) { return ModelParser.parseEnum(sourceClass); } else { return parseBean(sourceClass); } } private BeanModel parseBean(SourceType<Class<?>> sourceClass) { final List<PropertyModel> properties = new ArrayList<>(); final BeanHelper beanHelper = getBeanHelper(sourceClass.type); if (beanHelper != null) { for (BeanPropertyWriter beanPropertyWriter : beanHelper.getProperties()) { Type propertyType = beanPropertyWriter.getGenericPropertyType(); if (propertyType == JsonNode.class) { propertyType = Object.class; } boolean isInAnnotationFilter = settings.includePropertyAnnotations.isEmpty(); if (!isInAnnotationFilter) { for (Class<? extends Annotation> optionalAnnotation : settings.includePropertyAnnotations) { if (beanPropertyWriter.getAnnotation(optionalAnnotation) != null) { isInAnnotationFilter = true; break; } } if (!isInAnnotationFilter) { System.out.println("Skipping " + sourceClass.type + "." + beanPropertyWriter.getName() + " because it is missing an annotation from includePropertyAnnotations!"); continue; } } boolean optional = false; for (Class<? extends Annotation> optionalAnnotation : settings.optionalAnnotations) { if (beanPropertyWriter.getAnnotation(optionalAnnotation) != null) { optional = true; break; } } final Member originalMember = beanPropertyWriter.getMember().getMember(); properties.add(processTypeAndCreateProperty(beanPropertyWriter.getName(), propertyType, optional, sourceClass.type, originalMember, null)); } } final JsonTypeInfo jsonTypeInfo = sourceClass.type.getAnnotation(JsonTypeInfo.class); if (jsonTypeInfo != null && jsonTypeInfo.include() == JsonTypeInfo.As.PROPERTY) { if (!containsProperty(properties, jsonTypeInfo.property())) { properties.add(new PropertyModel(jsonTypeInfo.property(), String.class, false, null, null, null)); } } final JsonSubTypes jsonSubTypes = sourceClass.type.getAnnotation(JsonSubTypes.class); if (jsonSubTypes != null) { for (JsonSubTypes.Type type : jsonSubTypes.value()) { addBeanToQueue(new SourceType<>(type.value(), sourceClass.type, "<subClass>")); } } final Type superclass = sourceClass.type.getGenericSuperclass() == Object.class ? null : sourceClass.type.getGenericSuperclass(); if (superclass != null) { addBeanToQueue(new SourceType<>(superclass, sourceClass.type, "<superClass>")); } final List<Type> interfaces = Arrays.asList(sourceClass.type.getGenericInterfaces()); for (Type aInterface : interfaces) { addBeanToQueue(new SourceType<>(aInterface, sourceClass.type, "<interface>")); } return new BeanModel(sourceClass.type, superclass, null, null, null, interfaces, properties, null); } private BeanHelper getBeanHelper(Class<?> beanClass) { if (beanClass == null) { return null; } try { final SerializationConfig serializationConfig = objectMapper.getSerializationConfig(); final JavaType simpleType = objectMapper.constructType(beanClass); final JsonSerializer<?> jsonSerializer = BeanSerializerFactory.instance.createSerializer(serializationConfig, simpleType, null); if (jsonSerializer == null) { return null; } if (jsonSerializer instanceof BeanSerializer) { return new BeanHelper((BeanSerializer) jsonSerializer); } else { final String jsonSerializerName = jsonSerializer.getClass().getName(); throw new RuntimeException(String.format("Unknown serializer '%s' for class '%s'", jsonSerializerName, beanClass)); } } catch (JsonMappingException e) { throw new RuntimeException(e); } } private static class BeanHelper extends BeanSerializer { public BeanHelper(BeanSerializer src) { super(src); } public BeanPropertyWriter[] getProperties() { return _props; } } }