All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reflections.serializers.JavaCodeSerializer Maven / Gradle / Ivy

The newest version!
/**
 * Copyright © 2013 Sven Ruppert ([email protected])
 *
 * 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 org.reflections.serializers;

import org.rapidpm.dependencies.core.logger.Logger;
import org.rapidpm.dependencies.core.logger.LoggingService;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.ReflectionsException;
import org.reflections.scanners.TypeElementsScanner;
import org.reflections.util.Utils;
import repacked.com.google.common.base.Joiner;
import repacked.com.google.common.collect.Multimap;
import repacked.com.google.common.collect.Multimaps;
import repacked.com.google.common.io.Files;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Supplier;

import static org.reflections.util.Utils.prepareFile;
import static org.reflections.util.Utils.repeat;

public class JavaCodeSerializer implements Serializer {

  private static final String PATH_SEPARATOR = "_";
  private static final String DOUBLE_SEPARATOR = "__";
  private static final String DOT_SEPARATOR = ".";
  private static final String ARRAY_DESCRIPTOR = "$$";
  private static final String TOKEN_SEPARATOR = "_";

  public static Class resolveClass(final Class aClass) {
    try {
      return resolveClassOf(aClass);
    } catch (Exception e) {
      throw new ReflectionsException("could not resolve to class " + aClass.getName() , e);
    }
  }

  //
  public static Class resolveClassOf(final Class element) throws ClassNotFoundException {
    Class cursor = element;
    LinkedList ognl = new LinkedList<>();
    while (cursor != null) {
      ognl.addFirst(cursor.getSimpleName());
      cursor = cursor.getDeclaringClass();
    }

    String classOgnl = Joiner.on(".").join(ognl.subList(1 , ognl.size())).replace(".$" , "$");
    return Class.forName(classOgnl);
  }

  public static Field resolveField(final Class aField) {
    try {
      String name = aField.getSimpleName();
      Class declaringClass = aField.getDeclaringClass().getDeclaringClass();
      return resolveClassOf(declaringClass).getDeclaredField(name);
    } catch (Exception e) {
      throw new ReflectionsException("could not resolve to field " + aField.getName() , e);
    }
  }

  public static Annotation resolveAnnotation(Class annotation) {
    try {
      String name = annotation.getSimpleName().replace(PATH_SEPARATOR , DOT_SEPARATOR);
      Class declaringClass = annotation.getDeclaringClass().getDeclaringClass();
      Class aClass = resolveClassOf(declaringClass);
      Class aClass1 = (Class) ReflectionUtils.forName(name);
      Annotation annotation1 = aClass.getAnnotation(aClass1);
      return annotation1;
    } catch (Exception e) {
      throw new ReflectionsException("could not resolve to annotation " + annotation.getName() , e);
    }
  }

  public static Method resolveMethod(final Class aMethod) {
    String methodOgnl = aMethod.getSimpleName();

    try {
      String methodName;
      Class[] paramTypes;
      if (methodOgnl.contains(TOKEN_SEPARATOR)) {
        methodName = methodOgnl.substring(0 , methodOgnl.indexOf(TOKEN_SEPARATOR));
        String[] params = methodOgnl.substring(methodOgnl.indexOf(TOKEN_SEPARATOR) + 1).split(DOUBLE_SEPARATOR);
        paramTypes = new Class[params.length];
        for (int i = 0; i < params.length; i++) {
          String typeName = params[i].replace(ARRAY_DESCRIPTOR , "[]").replace(PATH_SEPARATOR , DOT_SEPARATOR);
          paramTypes[i] = ReflectionUtils.forName(typeName);
        }
      } else {
        methodName = methodOgnl;
        paramTypes = null;
      }

      Class declaringClass = aMethod.getDeclaringClass().getDeclaringClass();
      return resolveClassOf(declaringClass).getDeclaredMethod(methodName , paramTypes);
    } catch (Exception e) {
      throw new ReflectionsException("could not resolve to method " + aMethod.getName() , e);
    }
  }

  public Reflections read(InputStream inputStream) {
    throw new UnsupportedOperationException("read is not implemented on JavaCodeSerializer");
  }


  public File save(Reflections reflections , String name) {
    if (name.endsWith("/")) {
      name = name.substring(0 , name.length() - 1); //trim / at the end
    }

    //prepare file
    String filename = name.replace('.' , '/').concat(".java");
    File file = prepareFile(filename);

    //get package and class names
    String packageName;
    String className;
    int lastDot = name.lastIndexOf('.');
    if (lastDot == - 1) {
      packageName = "";
      className = name.substring(name.lastIndexOf('/') + 1);
    } else {
      packageName = name.substring(name.lastIndexOf('/') + 1 , lastDot);
      className = name.substring(lastDot + 1);
    }

    //generate
    try {
      StringBuilder sb = new StringBuilder();
      sb.append("//generated using Reflections JavaCodeSerializer")
        .append(" [").append(new Date()).append("]")
        .append("\n");
      if (packageName.length() != 0) {
        sb.append("package ").append(packageName).append(";\n");
        sb.append("\n");
      }
      sb.append("public interface ").append(className).append(" {\n\n");
      sb.append(toString(reflections));
      sb.append("}\n");

      Files.write(sb.toString() , new File(filename) , Charset.defaultCharset());

    } catch (IOException e) {
      throw new RuntimeException();
    }

    return file;
  }

  public String toString(Reflections reflections) {
    if (reflections.getStore().get(TypeElementsScanner.class.getSimpleName()).isEmpty()) {
      final LoggingService log = Logger.getLogger(Reflections.class);
      if (log != null) log.warning("JavaCodeSerializer needs TypeElementsScanner configured");
    }

    StringBuilder sb = new StringBuilder();

    List prevPaths = new ArrayList<>();
    int indent = 1;

    List keys = new ArrayList<>(reflections.getStore().get(TypeElementsScanner.class.getSimpleName()).keySet());
    Collections.sort(keys);
    for (String fqn : keys) {
      List typePaths = new ArrayList<>(Arrays.asList(fqn.split("\\.")));

      //skip indention
      int i = 0;
      while (i < Math.min(typePaths.size() , prevPaths.size()) && typePaths.get(i).equals(prevPaths.get(i))) {
        i++;
      }

      //indent left
      for (int j = prevPaths.size(); j > i; j--) {
        sb.append(repeat("\t" , -- indent)).append("}\n");
      }

      //indent right - add packages
      for (int j = i; j < typePaths.size() - 1; j++) {
        sb.append(repeat("\t" , indent++)).append("public interface ").append(getNonDuplicateName(typePaths.get(j) , typePaths , j)).append(" {\n");
      }

      //indent right - add class
      String className = typePaths.get(typePaths.size() - 1);

      //get fields and methods
      List annotations = new ArrayList<>();
      List fields = new ArrayList<>();


      final Map> map = new HashMap<>();

      final Supplier supplier = (Supplier>) HashSet::new;

      final Multimap methods = Multimaps.newSetMultimap(map , supplier);

      for (String element : reflections.getStore().get(TypeElementsScanner.class.getSimpleName() , fqn)) {
        if (element.startsWith("@")) {
          annotations.add(element.substring(1));
        } else if (element.contains("(")) {
          //method
          if (! element.startsWith("<")) {
            int i1 = element.indexOf('(');
            String name = element.substring(0 , i1);
            String params = element.substring(i1 + 1 , element.indexOf(")"));

            String paramsDescriptor = "";
            if (params.length() != 0) {
              paramsDescriptor = TOKEN_SEPARATOR + params.replace(DOT_SEPARATOR , TOKEN_SEPARATOR).replace(", " , DOUBLE_SEPARATOR).replace("[]" , ARRAY_DESCRIPTOR);
            }
            String normalized = name + paramsDescriptor;
            methods.put(name , normalized);
          }
        } else if (! Utils.isEmpty(element)) {
          //field
          fields.add(element);
        }
      }

      //add class and it's fields and methods
      sb.append(repeat("\t" , indent++)).append("public interface ").append(getNonDuplicateName(className , typePaths , typePaths.size() - 1)).append(" {\n");

      //add fields
      if (! fields.isEmpty()) {
        sb.append(repeat("\t" , indent++)).append("public interface fields {\n");
        for (String field : fields) {
          sb.append(repeat("\t" , indent)).append("public interface ").append(getNonDuplicateName(field , typePaths)).append(" {}\n");
        }
        sb.append(repeat("\t" , -- indent)).append("}\n");
      }

      //add methods
      if (! methods.isEmpty()) {
        sb.append(repeat("\t" , indent++)).append("public interface methods {\n");
        for (Map.Entry entry : methods.entries()) {
          String simpleName = entry.getKey();
          String normalized = entry.getValue();

          String methodName = methods.get(simpleName).size() == 1 ? simpleName : normalized;

          methodName = getNonDuplicateName(methodName , fields);

          sb.append(repeat("\t" , indent)).append("public interface ").append(getNonDuplicateName(methodName , typePaths)).append(" {}\n");
        }
        sb.append(repeat("\t" , -- indent)).append("}\n");
      }

      //add annotations
      if (! annotations.isEmpty()) {
        sb.append(repeat("\t" , indent++)).append("public interface annotations {\n");
        for (String annotation : annotations) {
          String nonDuplicateName = annotation;
          nonDuplicateName = getNonDuplicateName(nonDuplicateName , typePaths);
          sb.append(repeat("\t" , indent)).append("public interface ").append(nonDuplicateName).append(" {}\n");
        }
        sb.append(repeat("\t" , -- indent)).append("}\n");
      }

      prevPaths = typePaths;
    }


    //close indention
    for (int j = prevPaths.size(); j >= 1; j--) {
      sb.append(repeat("\t" , j)).append("}\n");
    }

    return sb.toString();
  }

  private String getNonDuplicateName(String candidate , List prev , int offset) {
    String normalized = normalize(candidate);
    for (int i = 0; i < offset; i++) {
      if (normalized.equals(prev.get(i))) {
        return getNonDuplicateName(normalized + TOKEN_SEPARATOR , prev , offset);
      }
    }

    return normalized;
  }

  private String normalize(String candidate) {
    return candidate.replace(DOT_SEPARATOR , PATH_SEPARATOR);
  }

  private String getNonDuplicateName(String candidate , List prev) {
    return getNonDuplicateName(candidate , prev , prev.size());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy