package com.jsoniter.annotation; import com.jsoniter.spi.JsonException; import com.jsoniter.spi.*; import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class JsoniterAnnotationSupport extends EmptyExtension { private static boolean enabled = false; public static void enable() { if (enabled) { return; } enabled = true; JsoniterSpi.registerExtension(new JsoniterAnnotationSupport()); } @Override public void updateClassDescriptor(ClassDescriptor desc) { JsonObject jsonObject = (JsonObject) desc.clazz.getAnnotation(JsonObject.class); if (jsonObject != null) { if (jsonObject.asExtraForUnknownProperties()) { desc.asExtraForUnknownProperties = true; } for (String fieldName : jsonObject.unknownPropertiesWhitelist()) { Binding binding = new Binding(desc.clazz, desc.lookup, Object.class); binding.name = fieldName; binding.shouldSkip = true; desc.fields.add(binding); } for (String fieldName : jsonObject.unknownPropertiesBlacklist()) { Binding binding = new Binding(desc.clazz, desc.lookup, Object.class); binding.name = fieldName; binding.asExtraWhenPresent = true; desc.fields.add(binding); } } List<Method> allMethods = new ArrayList<Method>(); Class current = desc.clazz; while (current != null) { allMethods.addAll(Arrays.asList(current.getDeclaredMethods())); current = current.getSuperclass(); } updateBindings(desc); detectCtor(desc); detectStaticFactory(desc, allMethods); detectWrappers(desc, allMethods); detectUnwrappers(desc, allMethods); } private void detectUnwrappers(ClassDescriptor desc, List<Method> allMethods) { for (Method method : allMethods) { if (Modifier.isStatic(method.getModifiers())) { continue; } if (method.getAnnotation(JsonUnwrapper.class) == null) { continue; } desc.unWrappers.add(method); } } private void detectWrappers(ClassDescriptor desc, List<Method> allMethods) { for (Method method : allMethods) { if (Modifier.isStatic(method.getModifiers())) { continue; } if (method.getAnnotation(JsonWrapper.class) == null) { continue; } Annotation[][] annotations = method.getParameterAnnotations(); String[] paramNames = getParamNames(method, annotations.length); WrapperDescriptor setter = new WrapperDescriptor(); setter.method = method; for (int i = 0; i < annotations.length; i++) { Annotation[] paramAnnotations = annotations[i]; Binding binding = new Binding(desc.clazz, desc.lookup, method.getGenericParameterTypes()[i]); JsonProperty jsonProperty = getJsonProperty(paramAnnotations); if (jsonProperty != null) { updateBindingWithJsonProperty(binding, jsonProperty); } if (binding.name == null || binding.name.length() == 0) { binding.name = paramNames[i]; } binding.annotations = paramAnnotations; setter.parameters.add(binding); } desc.wrappers.add(setter); } } private String[] getParamNames(Object obj, int paramCount) { String[] paramNames = new String[paramCount]; try { Object params = reflectCall(obj, "getParameters"); for (int i = 0; i < paramNames.length; i++) { paramNames[i] = (String) reflectCall(Array.get(params, i), "getName"); } } catch (Exception e) { } return paramNames; } private Object reflectCall(Object obj, String methodName, Object... args) throws Exception { Method method = obj.getClass().getMethod(methodName); return method.invoke(obj, args); } private void detectStaticFactory(ClassDescriptor desc, List<Method> allMethods) { for (Method method : allMethods) { if (!Modifier.isStatic(method.getModifiers())) { continue; } JsonCreator jsonCreator = getJsonCreator(method.getAnnotations()); if (jsonCreator == null) { continue; } desc.ctor.staticMethodName = method.getName(); desc.ctor.staticFactory = method; desc.ctor.ctor = null; Annotation[][] annotations = method.getParameterAnnotations(); String[] paramNames = getParamNames(method, annotations.length); for (int i = 0; i < annotations.length; i++) { Annotation[] paramAnnotations = annotations[i]; JsonProperty jsonProperty = getJsonProperty(paramAnnotations); Binding binding = new Binding(desc.clazz, desc.lookup, method.getGenericParameterTypes()[i]); if (jsonProperty != null) { updateBindingWithJsonProperty(binding, jsonProperty); } if (binding.name == null || binding.name.length() == 0) { binding.name = paramNames[i]; } binding.annotations = paramAnnotations; desc.ctor.parameters.add(binding); } } } private void detectCtor(ClassDescriptor desc) { for (Constructor ctor : desc.clazz.getDeclaredConstructors()) { JsonCreator jsonCreator = getJsonCreator(ctor.getAnnotations()); if (jsonCreator == null) { continue; } desc.ctor.staticMethodName = null; desc.ctor.ctor = ctor; desc.ctor.staticFactory = null; Annotation[][] annotations = ctor.getParameterAnnotations(); String[] paramNames = getParamNames(ctor, annotations.length); for (int i = 0; i < annotations.length; i++) { Annotation[] paramAnnotations = annotations[i]; JsonProperty jsonProperty = getJsonProperty(paramAnnotations); Binding binding = new Binding(desc.clazz, desc.lookup, ctor.getGenericParameterTypes()[i]); if (jsonProperty != null) { updateBindingWithJsonProperty(binding, jsonProperty); } if (binding.name == null || binding.name.length() == 0) { binding.name = paramNames[i]; } binding.annotations = paramAnnotations; desc.ctor.parameters.add(binding); } } } private void updateBindings(ClassDescriptor desc) { for (Binding binding : desc.allBindings()) { JsonIgnore jsonIgnore = getJsonIgnore(binding.annotations); if (jsonIgnore != null && jsonIgnore.value()) { binding.fromNames = new String[0]; binding.toNames = new String[0]; } JsonProperty jsonProperty = getJsonProperty(binding.annotations); if (jsonProperty != null) { updateBindingWithJsonProperty(binding, jsonProperty); } if (getAnnotation(binding.annotations, JsonMissingProperties.class) != null) { // this binding will not bind from json // instead it will be set by jsoniter with missing property names binding.fromNames = new String[0]; desc.onMissingProperties = binding; } if (getAnnotation(binding.annotations, JsonExtraProperties.class) != null) { // this binding will not bind from json // instead it will be set by jsoniter with extra properties binding.fromNames = new String[0]; desc.onExtraProperties = binding; } } } private void updateBindingWithJsonProperty(Binding binding, JsonProperty jsonProperty) { binding.asMissingWhenNotPresent = jsonProperty.required(); binding.isNullable = jsonProperty.nullable(); binding.isCollectionValueNullable = jsonProperty.collectionValueNullable(); binding.shouldOmitNull = jsonProperty.omitNull(); String altName = jsonProperty.value(); if (!altName.isEmpty()) { binding.name = altName; binding.fromNames = new String[]{altName}; } if (jsonProperty.from().length > 0) { binding.fromNames = jsonProperty.from(); } if (jsonProperty.to().length > 0) { binding.toNames = jsonProperty.to(); } if (jsonProperty.decoder() != Decoder.class) { try { binding.decoder = jsonProperty.decoder().newInstance(); } catch (Exception e) { throw new JsonException(e); } } if (jsonProperty.encoder() != Encoder.class) { try { binding.encoder = jsonProperty.encoder().newInstance(); } catch (Exception e) { throw new JsonException(e); } } if (jsonProperty.implementation() != Object.class) { binding.valueType = ParameterizedTypeImpl.useImpl(binding.valueType, jsonProperty.implementation()); binding.valueTypeLiteral = TypeLiteral.create(binding.valueType); } } protected JsonCreator getJsonCreator(Annotation[] annotations) { return getAnnotation(annotations, JsonCreator.class); } protected JsonProperty getJsonProperty(Annotation[] annotations) { return getAnnotation(annotations, JsonProperty.class); } protected JsonIgnore getJsonIgnore(Annotation[] annotations) { return getAnnotation(annotations, JsonIgnore.class); } protected static <T extends Annotation> T getAnnotation(Annotation[] annotations, Class<T> annotationClass) { if (annotations == null) { return null; } for (Annotation annotation : annotations) { if (annotationClass.isAssignableFrom(annotation.getClass())) { return (T) annotation; } } return null; } }