<commit_before>package com.masterdoc.plugin;

import static java.io.File.separator;
import static java.text.MessageFormat.format;
import static org.springframework.util.StringUtils.capitalize;

import java.beans.IntrospectionException;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.ws.rs.*;

import org.apache.camel.Consume;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.reflections.Reflections;

import com.googlecode.gentyref.GenericTypeReflector;
import com.masterdoc.pojo.*;
import com.masterdoc.pojo.Enumeration;

public class MasterDocGenerator {

  // ----------------------------------------------------------------------
  // Constants
  // ----------------------------------------------------------------------

  public static final String           CLASS                   = "class ";
  public static final SimpleDateFormat SDF                     = new SimpleDateFormat("dd-MM-yyyy HH:mm:sss");
  public static final String           MASTERDOC_JSON_FILENAME = "masterdoc.json";
  public static final String           PATH_PARAM              = "PathParam";
  public static final String           QUERY_PARAM             = "QueryParam";
  public static final String           JAVA_UTIL_HASH_MAP      = "java.util.HashMap";
  public static final String           GET                     = "GET";
  public static final String           POST                    = "POST";
  public static final String           PUT                     = "PUT";
  public static final String           DELETE                  = "DELETE";
  public static final String           OPTIONS                 = "OPTIONS";
  public static final String           NULL                    = "null";
  public static final String           VOID                    = "void";
  public static final String           IS_PREFIX               = "is";
  public static final String           GET_PREFIX              = "get";
  public static final String           INTERFACE               = "interface";
  public static final String           T                       = "T";
  public static final String           JAVA_LANG_OBJECT        = "java.lang.Object";
  public static final String           JAVA                    = "java";
  public static final String           BYTE                    = "B";
  public static final String           ARRAY                   = "[]";
  public static final String           DOT                     = ".";
  public static final String           COMMA                   = ",";

  // ----------------------------------------------------------------------
  // Variables
  // ----------------------------------------------------------------------
  /** Logger for maven plugin. */
  private ConsoleLogger                consoleLogger           = new ConsoleLogger();
  /** Resources found by MasterDoc. */
  private List<Resource>               resources;
  /** Entities found by MasterDoc. */
  private List<AbstractEntity>         entities;
  /** Metadata found by MasterDoc. */
  private MasterDocMetadata            metadata;
  /** Final MasterDoc. */
  private MasterDoc                    masterDoc;
  private Set<Serializable>            entityList;
  private MavenProject                 project;
  private ClassLoader                  originalClassLoader     = Thread.currentThread().getContextClassLoader();
  private ClassLoader                  newClassLoader;
  private String                       pathToGenerateFile;
  private HashSet<Serializable>        newEntities;

  // ----------------------------------------------------------------------
  // Constructors
  // ----------------------------------------------------------------------

  public MasterDocGenerator(MavenProject project, String pathToGenerateFile, String[] packageDocumentationResources)
      throws SecurityException,
      NoSuchFieldException,
      IllegalArgumentException, IllegalAccessException {
    long start = System.currentTimeMillis();
    consoleLogger.info("MasterDocGenerator started");
    resources = new ArrayList<Resource>();
    entities = new ArrayList<AbstractEntity>();
    entityList = new HashSet<Serializable>();
    this.project = project;
    this.pathToGenerateFile = pathToGenerateFile;
    // ////////////////////
    generateProjectClassLoader(project);
    // ////////////////////
    for (String packageDocumentationResource : packageDocumentationResources) {
      consoleLogger.info(format("Generate REST documentation on package {0} ...", packageDocumentationResource));
      startGeneration(new String[] { packageDocumentationResource });
    }
    //
    generateDocumentationFile();
    //
    // restore original classloader
    Thread.currentThread().setContextClassLoader(originalClassLoader);
    consoleLogger.info(format("Generation ended in {0} ms", (System.currentTimeMillis() - start)));
  }

  // ----------------------------------------------------------------------
  // Public methods
  // ----------------------------------------------------------------------
  public void startGeneration(String[] args) {
    String packageDocumentationResource = args[0];

    if (null != packageDocumentationResource
        && packageDocumentationResource.length() > 0) {
      try {
        getMetadata();
        getDocResource(packageDocumentationResource);
        getEntities(entityList);
        consoleLogger.info(format("Entities : {0}", entityList.size()));
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (IntrospectionException e) {
        e.printStackTrace();
      }
    } else {
      consoleLogger.error("packageDocumentationResources not defined in plugin configuration");
    }
  }

  // ----------------------------------------------------------------------
  // Private methods
  // ----------------------------------------------------------------------
  private void getEntities(Set list) throws ClassNotFoundException,
      IntrospectionException {

    newEntities = new HashSet<Serializable>();
    for (Iterator<Serializable> iterator = list.iterator(); iterator
        .hasNext();) {
      Serializable entity = iterator.next();
      final Class<?> entityClass;
      try {
        entityClass = Class.forName(entity.toString(), true, newClassLoader);
      } catch (Exception e) {
        consoleLogger.debug(format("{0} is not forNamable", entity.toString()));
        continue;
      }
      Entity newEntity = new Entity();
      if (!entity.toString().startsWith(JAVA)) {

        newEntity.setName(entity.toString());

        if (entityClass.isEnum()) {
          extractEnumFields(entity);
        } else {
          newEntity.setFields(extractFields(entity));
          final Class<?> superclass = entityClass.getSuperclass();
          if (!JAVA_LANG_OBJECT.equals(superclass.getName())) {
            newEntity.setSuperClass(superclass);
            if (!entityList.contains(superclass.getName()) && !newEntities.contains(superclass.getName())) {
              newEntities.add(superclass.getName());
            }
          }

          entities.add(newEntity);
        }
      }
    }
    if (newEntities.size() > 0) {
      entityList.addAll(newEntities);
      getEntities((Set) newEntities.clone());
    }
  }

  /**
   * Get all @Path class and export all methods
   * 
   * @throws NoSuchFieldException
   * @throws SecurityException
   */

  private void getDocResource(String packageDocumentationResource) {
    String mediaTypeProduces = null, mediaTypeConsumes = null;

    Reflections reflections = new Reflections(packageDocumentationResource);
    Set<Class<?>> reflectionResources = reflections
        .getTypesAnnotatedWith(Path.class);
    consoleLogger.info(format("Ressources : {0}", reflectionResources));
    for (Iterator<Class<?>> iterator = reflectionResources.iterator(); iterator
        .hasNext();) {
      Class<?> resource = iterator.next();
      if (!resource.isInterface()) {
        Resource res = new Resource();

        Annotation[] annotations = resource.getAnnotations();
        Method[] declaredMethods = resource.getDeclaredMethods();

        res.setEntryList(new TreeMap<String, ResourceEntry>());
        // Annotations for resource
        for (int i = 0; i < annotations.length; i++) {
          Annotation annotation = annotations[i];
          if (annotation instanceof Path) {
            res.setRootPath(((Path) annotation).value());
          }
          if (annotation instanceof Produces) {
            mediaTypeProduces = ((Produces) annotation).value()[0];
          }
          if (annotation instanceof Consumes) {
            mediaTypeConsumes = ((Consumes) annotation).value()[0];
          }
        }

        // Check methods
        Class<?> superclass = resource.getSuperclass();
        if (null != superclass
            && !superclass.getCanonicalName().equals(
                JAVA_LANG_OBJECT)) {
          Method[] superclassDeclaredMethods = superclass
              .getDeclaredMethods();
          for (int i = 0; i < superclassDeclaredMethods.length; i++) {
            Method superclassDeclaredMethod = superclassDeclaredMethods[i];
            ResourceEntry resourceEntry = createResourceEntryFromMethod(
                superclassDeclaredMethod, mediaTypeConsumes,
                mediaTypeProduces, resource);
            if (null != resourceEntry) {
              resourceEntry.setFullPath(res.getRootPath() + "/"
                  + resourceEntry.getPath());
              res.getEntryList().put(
                  resourceEntry.calculateUniqKey(),
                  resourceEntry);
            }
          }
        }
        for (int i = 0; i < declaredMethods.length; i++) {
          Method declaredMethod = declaredMethods[i];
          ResourceEntry resourceEntry = createResourceEntryFromMethod(
              declaredMethod, mediaTypeConsumes,
              mediaTypeProduces, null);
          if (null != resourceEntry) {
            if (res.getEntryList().containsKey(
                resourceEntry.calculateUniqKey())) {
              res.getEntryList().remove(
                  resourceEntry.calculateUniqKey());
            }
            resourceEntry.setFullPath(res.getRootPath() + "/"
                + resourceEntry.getPath());
            res.getEntryList()
                .put(resourceEntry.calculateUniqKey(),
                    resourceEntry);
          }
        }

        consoleLogger.debug(">> " + resource.getCanonicalName());
        resources.add(res);
        extractEntityFromResourceEntries(res);
      } else {
        consoleLogger.debug(">>skip " + resource.getCanonicalName());
      }
    }
  }

  private void getMetadata() {
    metadata = new MasterDocMetadata();
    metadata.setGenerationDate(SDF.format(new Date()));
    metadata.setGroupId(project.getGroupId());
    metadata.setArtifactId(project.getArtifactId());
    metadata.setVersion(project.getVersion());

  }

  /**
   * Method to switch from class OR enum
   * 
   * @param entity
   * @return
   * @throws ClassNotFoundException
   * @throws IntrospectionException
   */
  private Map<String, AbstractEntity> extractFieldsSwitcher(
      Serializable entity) throws ClassNotFoundException,
      IntrospectionException {
    final Class<?> entityClass;
    try {
      entityClass = Class.forName(entity.toString(), true, newClassLoader);
    } catch (Exception e) {
      consoleLogger.debug(format("{0} is not forNamable", entity.toString()));
      return null;
    }
    if (entityClass.isEnum()) {
      return extractEnumFields(entity);
    } else {
      return extractFields(entity);
    }
  }

  /**
   * Method to extract the class values.
   * 
   * @param entity
   * @return
   * @throws ClassNotFoundException
   * @throws IntrospectionException
   */
  private Map<String, AbstractEntity> extractFields(Serializable entity)
      throws ClassNotFoundException, IntrospectionException {
    Map<String, AbstractEntity> fields = new HashMap<String, AbstractEntity>();
    final Class<?> entityClass = Class.forName(entity.toString(), true, newClassLoader);
    consoleLogger.debug(format(">>Extract fields for class {0} ...", entityClass));

    final java.lang.reflect.Field[] declaredFields = entityClass
        .getDeclaredFields();
    for (int i = 0; i < declaredFields.length; i++) {
      java.lang.reflect.Field declaredField = declaredFields[i];
      consoleLogger.debug(format(">>Extract fields  {0} ...", declaredField.getName()));
      Type typeOfField = declaredField.getGenericType();
      if (!typeOfField.toString().startsWith(CLASS) &&
          !typeOfField.toString().startsWith(INTERFACE) &&
          typeOfField.toString().indexOf(DOT) > -1) {
        typeOfField = (ParameterizedType) typeOfField;
      }
      String type = extractTypeFromType(typeOfField);
      String typeDisplay = type;
      if (type.startsWith("[")) {
        if (type.startsWith("[L") && type.endsWith(";")) {
          type = type.substring(2, type.length() - 1);
        } else {
          type = type.substring(1);
          if (BYTE.equals(type)) {
            type = byte.class.getName();
          }
        }
        typeDisplay = type + ARRAY;
      }
      if (type.indexOf("<") > -1) {
        type = type.substring(type.indexOf("<") + 1, type.indexOf(">"));
      }
      String[] types = type.split(COMMA);
      try {
        entityClass.getDeclaredMethod(GET_PREFIX + capitalize(declaredField.getName())); // GET OR IS
        Class<?> currEntityClass = null;
        for (String t : types) {
          try {
            t = t.trim();
            currEntityClass = Class.forName(t, true, newClassLoader);
            if (!entityList.contains(t) && !newEntities.contains(t)) {
              newEntities.add(t);
            }
          } catch (Exception e) {
            consoleLogger.debug(format("{0} is not forNamable", t.toString()));
            continue;
          }
        }
        AbstractEntity field;
        if (null != currEntityClass && currEntityClass.isEnum()) {
          field = new Enumeration();
          field.setName(typeDisplay);
        } else {
          field = new Entity();
          field.setName(typeDisplay);
        }
        fields.put(declaredField.getName(), field);

      } catch (NoSuchMethodException e) {
        try {
          entityClass.getDeclaredMethod(IS_PREFIX
              + capitalize(declaredField.getName())); // GET OR IS
          Entity field = new Entity();
          field.setName(declaredField.getName());
          final Class<?> currEntityClass;
          try {
            currEntityClass = Class.forName(type, true, newClassLoader);
          } catch (Exception e2) {
            consoleLogger.debug(format("{0} is not forNamable", entity.toString()));
            continue;
          }
          fields.put(declaredField.getName(), field);
          if (!entityList.contains(type)) {
            if (currEntityClass.isEnum()) {
              Enumeration newEnum = new Enumeration();
              newEnum.setName(field.getName());
            }
            Entity newEntity = new Entity();
            newEntity.setName(field.getName());
            newEntity.setFields(extractFieldsSwitcher(type));
          }
        } catch (NoSuchMethodException ex) {
          consoleLogger.debug(format(">>>>Bypass : {0}.{1}", entityClass.toString(), declaredField.getName()));
        }

      }
    }
    return fields;
  }

  /**
   * Method to extract the enuration values.
   * 
   * @param entity<commit_msg>Fix pb with boolean and isXXX method<commit_after>package com.masterdoc.plugin;

import static java.io.File.separator;
import static java.text.MessageFormat.format;
import static org.springframework.util.StringUtils.capitalize;

import java.beans.IntrospectionException;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.ws.rs.*;

import org.apache.camel.Consume;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.reflections.Reflections;

import com.googlecode.gentyref.GenericTypeReflector;
import com.masterdoc.pojo.*;
import com.masterdoc.pojo.Enumeration;

public class MasterDocGenerator {

  // ----------------------------------------------------------------------
  // Constants
  // ----------------------------------------------------------------------

  public static final String           CLASS                   = "class ";
  public static final SimpleDateFormat SDF                     = new SimpleDateFormat("dd-MM-yyyy HH:mm:sss");
  public static final String           MASTERDOC_JSON_FILENAME = "masterdoc.json";
  public static final String           PATH_PARAM              = "PathParam";
  public static final String           QUERY_PARAM             = "QueryParam";
  public static final String           JAVA_UTIL_HASH_MAP      = "java.util.HashMap";
  public static final String           GET                     = "GET";
  public static final String           POST                    = "POST";
  public static final String           PUT                     = "PUT";
  public static final String           DELETE                  = "DELETE";
  public static final String           OPTIONS                 = "OPTIONS";
  public static final String           NULL                    = "null";
  public static final String           VOID                    = "void";
  public static final String           IS_PREFIX               = "is";
  public static final String           GET_PREFIX              = "get";
  public static final String           INTERFACE               = "interface";
  public static final String           T                       = "T";
  public static final String           JAVA_LANG_OBJECT        = "java.lang.Object";
  public static final String           JAVA                    = "java";
  public static final String           BYTE                    = "B";
  public static final String           ARRAY                   = "[]";
  public static final String           DOT                     = ".";
  public static final String           COMMA                   = ",";

  // ----------------------------------------------------------------------
  // Variables
  // ----------------------------------------------------------------------
  /** Logger for maven plugin. */
  private ConsoleLogger                consoleLogger           = new ConsoleLogger();
  /** Resources found by MasterDoc. */
  private List<Resource>               resources;
  /** Entities found by MasterDoc. */
  private List<AbstractEntity>         entities;
  /** Metadata found by MasterDoc. */
  private MasterDocMetadata            metadata;
  /** Final MasterDoc. */
  private MasterDoc                    masterDoc;
  private Set<Serializable>            entityList;
  private MavenProject                 project;
  private ClassLoader                  originalClassLoader     = Thread.currentThread().getContextClassLoader();
  private ClassLoader                  newClassLoader;
  private String                       pathToGenerateFile;
  private HashSet<Serializable>        newEntities;

  // ----------------------------------------------------------------------
  // Constructors
  // ----------------------------------------------------------------------

  public MasterDocGenerator(MavenProject project, String pathToGenerateFile, String[] packageDocumentationResources)
      throws SecurityException,
      NoSuchFieldException,
      IllegalArgumentException, IllegalAccessException {
    long start = System.currentTimeMillis();
    consoleLogger.info("MasterDocGenerator started");
    resources = new ArrayList<Resource>();
    entities = new ArrayList<AbstractEntity>();
    entityList = new HashSet<Serializable>();
    this.project = project;
    this.pathToGenerateFile = pathToGenerateFile;
    // ////////////////////
    generateProjectClassLoader(project);
    // ////////////////////
    for (String packageDocumentationResource : packageDocumentationResources) {
      consoleLogger.info(format("Generate REST documentation on package {0} ...", packageDocumentationResource));
      startGeneration(new String[] { packageDocumentationResource });
    }
    //
    generateDocumentationFile();
    //
    // restore original classloader
    Thread.currentThread().setContextClassLoader(originalClassLoader);
    consoleLogger.info(format("Generation ended in {0} ms", (System.currentTimeMillis() - start)));
  }

  // ----------------------------------------------------------------------
  // Public methods
  // ----------------------------------------------------------------------
  public void startGeneration(String[] args) {
    String packageDocumentationResource = args[0];

    if (null != packageDocumentationResource
        && packageDocumentationResource.length() > 0) {
      try {
        getMetadata();
        getDocResource(packageDocumentationResource);
        getEntities(entityList);
        consoleLogger.info(format("Entities : {0}", entityList.size()));
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (IntrospectionException e) {
        e.printStackTrace();
      }
    } else {
      consoleLogger.error("packageDocumentationResources not defined in plugin configuration");
    }
  }

  // ----------------------------------------------------------------------
  // Private methods
  // ----------------------------------------------------------------------
  private void getEntities(Set list) throws ClassNotFoundException,
      IntrospectionException {

    newEntities = new HashSet<Serializable>();
    for (Iterator<Serializable> iterator = list.iterator(); iterator
        .hasNext();) {
      Serializable entity = iterator.next();
      final Class<?> entityClass;
      try {
        entityClass = Class.forName(entity.toString(), true, newClassLoader);
      } catch (Exception e) {
        consoleLogger.debug(format("{0} is not forNamable", entity.toString()));
        continue;
      }
      Entity newEntity = new Entity();
      if (!entity.toString().startsWith(JAVA)) {

        newEntity.setName(entity.toString());

        if (entityClass.isEnum()) {
          extractEnumFields(entity);
        } else {
          newEntity.setFields(extractFields(entity));
          final Class<?> superclass = entityClass.getSuperclass();
          if (!JAVA_LANG_OBJECT.equals(superclass.getName())) {
            newEntity.setSuperClass(superclass);
            if (!entityList.contains(superclass.getName()) && !newEntities.contains(superclass.getName())) {
              newEntities.add(superclass.getName());
            }
          }

          entities.add(newEntity);
        }
      }
    }
    if (newEntities.size() > 0) {
      entityList.addAll(newEntities);
      getEntities((Set) newEntities.clone());
    }
  }

  /**
   * Get all @Path class and export all methods
   * 
   * @throws NoSuchFieldException
   * @throws SecurityException
   */

  private void getDocResource(String packageDocumentationResource) {
    String mediaTypeProduces = null, mediaTypeConsumes = null;

    Reflections reflections = new Reflections(packageDocumentationResource);
    Set<Class<?>> reflectionResources = reflections
        .getTypesAnnotatedWith(Path.class);
    consoleLogger.info(format("Ressources : {0}", reflectionResources));
    for (Iterator<Class<?>> iterator = reflectionResources.iterator(); iterator
        .hasNext();) {
      Class<?> resource = iterator.next();
      if (!resource.isInterface()) {
        Resource res = new Resource();

        Annotation[] annotations = resource.getAnnotations();
        Method[] declaredMethods = resource.getDeclaredMethods();

        res.setEntryList(new TreeMap<String, ResourceEntry>());
        // Annotations for resource
        for (int i = 0; i < annotations.length; i++) {
          Annotation annotation = annotations[i];
          if (annotation instanceof Path) {
            res.setRootPath(((Path) annotation).value());
          }
          if (annotation instanceof Produces) {
            mediaTypeProduces = ((Produces) annotation).value()[0];
          }
          if (annotation instanceof Consumes) {
            mediaTypeConsumes = ((Consumes) annotation).value()[0];
          }
        }

        // Check methods
        Class<?> superclass = resource.getSuperclass();
        if (null != superclass
            && !superclass.getCanonicalName().equals(
                JAVA_LANG_OBJECT)) {
          Method[] superclassDeclaredMethods = superclass
              .getDeclaredMethods();
          for (int i = 0; i < superclassDeclaredMethods.length; i++) {
            Method superclassDeclaredMethod = superclassDeclaredMethods[i];
            ResourceEntry resourceEntry = createResourceEntryFromMethod(
                superclassDeclaredMethod, mediaTypeConsumes,
                mediaTypeProduces, resource);
            if (null != resourceEntry) {
              resourceEntry.setFullPath(res.getRootPath() + "/"
                  + resourceEntry.getPath());
              res.getEntryList().put(
                  resourceEntry.calculateUniqKey(),
                  resourceEntry);
            }
          }
        }
        for (int i = 0; i < declaredMethods.length; i++) {
          Method declaredMethod = declaredMethods[i];
          ResourceEntry resourceEntry = createResourceEntryFromMethod(
              declaredMethod, mediaTypeConsumes,
              mediaTypeProduces, null);
          if (null != resourceEntry) {
            if (res.getEntryList().containsKey(
                resourceEntry.calculateUniqKey())) {
              res.getEntryList().remove(
                  resourceEntry.calculateUniqKey());
            }
            resourceEntry.setFullPath(res.getRootPath() + "/"
                + resourceEntry.getPath());
            res.getEntryList()
                .put(resourceEntry.calculateUniqKey(),
                    resourceEntry);
          }
        }

        consoleLogger.debug(">> " + resource.getCanonicalName());
        resources.add(res);
        extractEntityFromResourceEntries(res);
      } else {
        consoleLogger.debug(">>skip " + resource.getCanonicalName());
      }
    }
  }

  private void getMetadata() {
    metadata = new MasterDocMetadata();
    metadata.setGenerationDate(SDF.format(new Date()));
    metadata.setGroupId(project.getGroupId());
    metadata.setArtifactId(project.getArtifactId());
    metadata.setVersion(project.getVersion());

  }

  /**
   * Method to switch from class OR enum
   * 
   * @param entity
   * @return
   * @throws ClassNotFoundException
   * @throws IntrospectionException
   */
  private Map<String, AbstractEntity> extractFieldsSwitcher(
      Serializable entity) throws ClassNotFoundException,
      IntrospectionException {
    final Class<?> entityClass;
    try {
      entityClass = Class.forName(entity.toString(), true, newClassLoader);
    } catch (Exception e) {
      consoleLogger.debug(format("{0} is not forNamable", entity.toString()));
      return null;
    }
    if (entityClass.isEnum()) {
      return extractEnumFields(entity);
    } else {
      return extractFields(entity);
    }
  }

  /**
   * Method to extract the class values.
   * 
   * @param entity
   * @return
   * @throws ClassNotFoundException
   * @throws IntrospectionException
   */
  private Map<String, AbstractEntity> extractFields(Serializable entity)
      throws ClassNotFoundException, IntrospectionException {
    Map<String, AbstractEntity> fields = new HashMap<String, AbstractEntity>();
    final Class<?> entityClass = Class.forName(entity.toString(), true, newClassLoader);
    consoleLogger.debug(format(">>Extract fields for class {0} ...", entityClass));

    final java.lang.reflect.Field[] declaredFields = entityClass
        .getDeclaredFields();
    for (int i = 0; i < declaredFields.length; i++) {
      java.lang.reflect.Field declaredField = declaredFields[i];
      consoleLogger.debug(format(">>Extract fields  {0} ...", declaredField.getName()));
      Type typeOfField = declaredField.getGenericType();
      if (!typeOfField.toString().startsWith(CLASS) &&
          !typeOfField.toString().startsWith(INTERFACE) &&
          typeOfField.toString().indexOf(DOT) > -1) {
        typeOfField = (ParameterizedType) typeOfField;
      }
      String type = extractTypeFromType(typeOfField);
      String typeDisplay = type;
      if (type.startsWith("[")) {
        if (type.startsWith("[L") && type.endsWith(";")) {
          type = type.substring(2, type.length() - 1);
        } else {
          type = type.substring(1);
          if (BYTE.equals(type)) {
            type = byte.class.getName();
          }
        }
        typeDisplay = type + ARRAY;
      }
      if (type.indexOf("<") > -1) {
        type = type.substring(type.indexOf("<") + 1, type.indexOf(">"));
      }
      String[] types = type.split(COMMA);
      try {
        entityClass.getDeclaredMethod(GET_PREFIX + capitalize(declaredField.getName())); // GET OR IS
        createEntityFromField(fields, declaredField, typeDisplay, types);

      } catch (NoSuchMethodException e) {
        try {
          entityClass.getDeclaredMethod(IS_PREFIX
              + capitalize(declaredField.getName())); // GET OR IS
          createEntityFromField(fields, declaredField, typeDisplay, types);

        } catch (NoSuchMethodException ex) {
          consoleLogger.debug(format(">>>>Bypass : {0}.{1}", entityClass.toString(), declaredField.getName()));
        }

      }
    }
    return fields;
  }

  private void createEntityFromField(Map<String, AbstractEntity> fields, Field declaredField, String typeDisplay, String[] types) {
    Class<?> currEntityClass = null;
    for (String t : types) {
      try {
        t = t.trim();
        currEntityClass = Class.forName(t, true, newClassLoader);
        if (!entityList.contains(t) && !newEntities.contains(t)) {
          newEntities.add(t);
        }
      } catch (Exception e) {
        consoleLogger.debug(format("{0} is not forNamable", t.toString()));
        continue;
      }
    }
    AbstractEntity field;
    if (null != currEntityClass && currEntityClass.isEnum()) {
      field = new Enumeration();
      field.setName(typeDisplay);
    } else {
      field = new Entity();
      field.setName(typeDisplay);
    }
    fields.put(declaredField.getName(), field);
  }

  /**
   * Method to extract the enuration values.
   * 
   * @param entity
{'fraction_non_alphanumeric': 0.1510890015625498, 'fraction_numerical': 0.0017219936860231513, 'mean_word_length': 2.0337622134081457, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1789386', 'n_tokens_mistral': 7751, 'n_tokens_neox': 7633, 'n_words': 1697}