com.itametis.jsonconverter.classpathscan.JsonMappingPackage.java Source code

Java tutorial

Introduction

Here is the source code for com.itametis.jsonconverter.classpathscan.JsonMappingPackage.java

Source

/* This file is part of JsonLegacyKiller.
 *
 * JsonLegacyKiller is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JsonLegacyKiller is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JsonLegacyKiller.  If not, see <http://www.gnu.org/licenses/gpl.txt >.
 *
 * If you need to develop a closed-source software, please contact us
 * at 'social@itametis.com' to get a commercial version of JsonLegacyKiller,
 * with a proprietary license instead.
 */
package com.itametis.jsonconverter.classpathscan;

import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import com.itametis.jsonconverter.annotation.JsonField;
import com.itametis.jsonconverter.annotation.JsonPath;
import com.itametis.jsonconverter.annotation.Jsonnable;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Singleton class containing the information about the Jsonnable content.
 *
 * @author <a href="mailto:chloe.mahalin@itametis.com">Chlo MAHALIN - ITAMETIS</a>
 */
public class JsonMappingPackage {

    private final static Logger LOGGER = LoggerFactory.getLogger(JsonMappingPackage.class.getSimpleName());

    private final static JsonMappingPackage INSTANCE = new JsonMappingPackage();

    private String packageToScan;

    /**
     * Map containing the name of the jsonnable class and the class.
     */
    private final HashMap<Type, ScannedClass> jsonnableClasses = new HashMap<>();

    /**
     * Constructor.
     */
    private JsonMappingPackage() {
        super();
    }

    /**
     * Call to unique instance.
     *
     * @return the singleton.
     */
    public static JsonMappingPackage getInstance() {
        return JsonMappingPackage.INSTANCE;
    }

    /**
     * Scan the current classpath looking for Json annotations.
     *
     * @param packageName the Package Name.
     */
    public void setPackageToScan(String packageName) {
        if (packageName != null && !packageName.isEmpty()) {
            packageName = packageName.replaceAll("/", ".");
            this.packageToScan = packageName;
        }
    }

    /**
     * Return the Jsonnable content in the application (defined using the constructor of JsonConverter).
     * The key of the map is the class definition.
     * The value, the detail about the jsonnable content.
     *
     * @return a collection containing all details about jsonnable content.
     */
    public Map<Type, ScannedClass> getJsonnableContent() {
        return this.jsonnableClasses;
    }

    /**
     * Scan the classes in the declared package (full class path otherwise) to find classes with Json annotations.
     * Get them in memory.
     *
     * @throws IOException
     */
    public final void scanClassesInPackage() throws IOException {
        this.jsonnableClasses.clear();

        //Get current class loader.
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        //Get Classpath.
        ClassPath classpath = ClassPath.from(classLoader);

        //Get Classes.
        ImmutableSet<ClassInfo> classes = this.getClassesFromClassPath(classpath);

        this.getJsonnableInformation(classes);
    }

    /**
     * Get all classes from class path depending on the declaration of a specific classpath.
     *
     * @param classpath the class path to investigate.
     *
     * @return the classes.
     */
    private ImmutableSet<ClassInfo> getClassesFromClassPath(ClassPath classpath) {
        if (this.packageToScan == null || this.packageToScan.isEmpty()) {
            return classpath.getAllClasses();
        } else {
            return classpath.getTopLevelClassesRecursive(this.packageToScan);
        }
    }

    /**
     * Get the Jsonnable Class info once and use them all along application life style.
     *
     * @param classes the classes found in the specified package.
     */
    private void getJsonnableInformation(ImmutableSet<ClassInfo> classes) {
        for (ClassInfo info : classes) {

            //Get all Jsonnable Classes.
            if (info.load().isAnnotationPresent(Jsonnable.class)) {
                Jsonnable annotation = info.load().getAnnotation(Jsonnable.class);

                ScannedClass jsonnable = new ScannedClass(
                        annotation.value().isEmpty() ? info.getSimpleName() : annotation.value(), info.load());

                this.addJsonnableClassFieldInInformation(info, jsonnable);

                this.jsonnableClasses.put(info.load(), jsonnable);
            }
        }
    }

    /**
     * Get the Jsonnable fields info.
     *
     * @param info      the info of the class.
     * @param jsonnable the Jsonnable class.
     */
    private void addJsonnableClassFieldInInformation(ClassInfo info, ScannedClass jsonnable) {
        //Get all Jsonnable fields in this jsonnable class
        for (Field field : info.load().getDeclaredFields()) {
            field.setAccessible(true);

            if (field.isAnnotationPresent(JsonField.class)) {
                JsonField fieldAnnotation = field.getAnnotation(JsonField.class);

                ScannedField jsonnableField = new ScannedField(
                        fieldAnnotation.name().isEmpty() ? field.getName() : fieldAnnotation.name(),
                        fieldAnnotation.nameInJson().isEmpty() ? field.getName() : fieldAnnotation.nameInJson(),
                        field);

                //In case Field is a collection.
                if (Collection.class.isAssignableFrom(field.getType())
                        || Map.class.isAssignableFrom(field.getType())) {
                    jsonnableField.setIsCollectionOrMap(true);
                    Type type = field.getGenericType();
                    //TODO : find something else.
                    if (type instanceof ParameterizedType) {
                        ParameterizedType pType = (ParameterizedType) type;
                        for (Type actualType : pType.getActualTypeArguments()) {
                            jsonnableField.addParameter(actualType);
                        }
                    }
                }

                if (field.isAnnotationPresent(JsonPath.class)) {
                    jsonnableField.setPathInCode(field.getAnnotation(JsonPath.class).pathInCode());
                    jsonnableField.setPathInJson(field.getAnnotation(JsonPath.class).pathInJson());
                }

                jsonnable.addField(jsonnableField);
            }

            field.setAccessible(false);
        }
    }

}