java2typescript.jackson.module.visitors.TSJsonObjectFormatVisitor.java Source code

Java tutorial

Introduction

Here is the source code for java2typescript.jackson.module.visitors.TSJsonObjectFormatVisitor.java

Source

/*******************************************************************************
 * Copyright 2013 Raphael Jolivet
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package java2typescript.jackson.module.visitors;

import static com.fasterxml.jackson.databind.PropertyName.NO_NAME;
import static java.lang.reflect.Modifier.isPublic;
import static java2typescript.jackson.module.visitors.TSJsonFormatVisitorWrapper.getTSTypeForHandler;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.Transient;
import java.lang.reflect.Method;
import java2typescript.jackson.module.grammar.AnyType;
import java2typescript.jackson.module.grammar.FunctionType;
import java2typescript.jackson.module.grammar.ClassType;
import java2typescript.jackson.module.grammar.VoidType;
import java2typescript.jackson.module.grammar.base.AbstractType;

import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.introspect.AnnotationMap;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.type.TypeBindings;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java2typescript.jackson.module.Configuration;

public class TSJsonObjectFormatVisitor extends ABaseTSJsonFormatVisitor<ClassType>
        implements JsonObjectFormatVisitor {

    private Class clazz;

    public TSJsonObjectFormatVisitor(ABaseTSJsonFormatVisitor<?> parentHolder, String className, Class clazz,
            Configuration conf) {
        super(parentHolder, conf);
        type = new ClassType(className, clazz);
        this.clazz = clazz;
    }

    private void addField(String name, AbstractType fieldType) {
        type.getFields().put(name, fieldType);
    }

    private boolean isAccessorMethod(Method method, BeanInfo beanInfo) {
        for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
            if (method.equals(property.getReadMethod())) {
                return true;
            }
            if (method.equals(property.getWriteMethod())) {
                return true;
            }
        }
        return false;
    }

    void addPublicMethods() {

        for (Method method : this.clazz.getDeclaredMethods()) {

            // Only public
            if (!isPublic(method.getModifiers())) {
                continue;
            }

            // Exclude accessors
            try {
                BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
                if (isAccessorMethod(method, beanInfo)) {
                    continue;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            if (conf.isIgnoredMethod(method)) {
                continue;
            }

            addMethod(method);
        }
    }

    private AbstractType getTSTypeForClass(AnnotatedMember member) {

        TypeBindings bindings = new TypeBindings(TypeFactory.defaultInstance(), member.getDeclaringClass());
        JavaType javaType = member.getType(bindings);
        if (javaType.getRawClass().getSimpleName().equals("Observable")) {
            javaType = javaType.containedType(0);
        }

        BeanProperty prop = new BeanProperty.Std(member.getName(), javaType, NO_NAME, new AnnotationMap(), member,
                false);

        try {
            return getTSTypeForProperty(prop);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e);
        }
    }

    private void addMethod(Method method) {
        FunctionType function = new FunctionType();

        AnnotatedMethod annotMethod = new AnnotatedMethod(null, method, new AnnotationMap(), null);

        function.setResultType(getTSTypeForClass(annotMethod));
        for (int i = 0; i < annotMethod.getParameterCount(); i++) {
            AnnotatedParameter param = annotMethod.getParameter(i);
            String name = "param" + i;
            function.getParameters().put(name, getTSTypeForClass(param));
        }
        this.type.getMethods().put(method.getName(), function);
    }

    @Override
    public void property(BeanProperty writer) throws JsonMappingException {
        addField(writer.getName(), getTSTypeForProperty(writer));
    }

    @Override
    public void property(String name, JsonFormatVisitable handler, JavaType propertyTypeHint)
            throws JsonMappingException {
        addField(name, getTSTypeForHandler(this, handler, propertyTypeHint, conf));
    }

    @Override
    public void optionalProperty(BeanProperty writer) throws JsonMappingException {
        addField(writer.getName(), getTSTypeForProperty(writer));
    }

    @Override
    public void optionalProperty(String name, JsonFormatVisitable handler, JavaType propertyTypeHint)
            throws JsonMappingException {
        addField(name, getTSTypeForHandler(this, handler, propertyTypeHint, conf));
    }

    protected AbstractType getTSTypeForProperty(BeanProperty writer) throws JsonMappingException {
        if (writer == null) {
            throw new IllegalArgumentException("Null writer");
        }
        JavaType type = writer.getType();
        if (type.getRawClass().equals(Void.TYPE)) {
            return VoidType.getInstance();
        }

        AbstractType customType = conf.getCustomTypes().get(type.getRawClass().getName());
        if (customType != null) {
            return customType;
        }

        try {
            JsonSerializer<Object> ser = getSer(writer);

            if (ser != null) {
                if (type == null) {
                    throw new IllegalStateException("Missing type for property '" + writer.getName() + "'");
                }
                return getTSTypeForHandler(this, ser, type, conf);
            } else {
                return AnyType.getInstance();
            }

        } catch (Exception e) {
            throw new RuntimeException(String.format(//
                    "Error when serializing %s, you should add a custom mapping for it", type.getRawClass()), e);
        }

    }

    protected JsonSerializer<java.lang.Object> getSer(BeanProperty writer) throws JsonMappingException {
        JsonSerializer<Object> ser = null;
        if (writer instanceof BeanPropertyWriter) {
            ser = ((BeanPropertyWriter) writer).getSerializer();
        }
        if (ser == null) {
            ser = getProvider().findValueSerializer(writer.getType(), writer);
        }
        return ser;
    }

}