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

org.swat.spring.SingletonVerifier Maven / Gradle / Ivy

There is a newer version: 6.0.1
Show newest version
/*
 * Copyright © 2018 Swatantra Agrawal. All rights reserved.
 */

package org.swat.spring;

import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;


/**
 * The type Singleton verifier.
 */
public class SingletonVerifier {
  private final String basePackage;
  private Class[] springAnnotations =
      new Class[]{Component.class, Controller.class, Repository.class, Service.class};

  /**
   * Instantiates a new Singleton verifier.
   *
   * @param baseBackage the base backage
   */
  public SingletonVerifier(String baseBackage) {
    this.basePackage = baseBackage;
  }

  /**
   * Fail on instance fields.
   */
  public void failOnInstanceFields() {
    final Set instanceFields = getInstanceFields();
    if (!instanceFields.isEmpty()) {
      System.out.println("=============================");
      System.out.println("Instance level fields are defined in a Singleton Object");
      int counter = 0;
      for (Field field : instanceFields) {
        System.out.println(++counter + "\t" + field);
      }
      System.out.println("=============================");
      System.out.println("Instance variables found in Singleton Objects. Check above logs.");
    }
    assert instanceFields.isEmpty();
  }

  /**
   * Gets instance fields.
   *
   * @return the instance fields
   */
  public Set getInstanceFields() {
    final Set instanceFields = new HashSet<>();
    Set> services = new HashSet<>();
    for (Class clazz : springAnnotations) {
      services.addAll(new Reflections(basePackage).getTypesAnnotatedWith(clazz));
    }
    for (Class service : services) {
      instanceFields.addAll(getInstanceFields(service));
    }
    return instanceFields;
  }

  /**
   * Is test class boolean.
   *
   * @param service the service
   * @return the boolean
   */
  public static boolean isTestClass(Class service) {
    File file = new File(".");
    String fileName = service.getName();
    return isTestClass(file, fileName, 2);
  }

  /**
   * Is test class boolean.
   *
   * @param folder   the folder
   * @param fileName the file name
   * @param depth    the depth
   * @return the boolean
   */
  public static boolean isTestClass(File folder, String fileName, int depth) {
    if (depth < 0) {
      return false;
    }
    if (!folder.isDirectory()) {
      return false;
    }
    if (new File(folder, fileName).exists()) {
      return true;
    }
    File[] files = folder.listFiles();
    if (files == null) {
      return false;
    }
    for (File file : files) {
      if (isTestClass(file, fileName, depth - 1)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Populate fields.
   *
   * @param clazz  the clazz
   * @param fields the fields
   */
  public static void populateFields(Class clazz, Set fields) {
    if (clazz == null || clazz == Object.class) {
      return;
    }
    Field[] declaredFields = clazz.getDeclaredFields();
    if (declaredFields != null) {
      Collections.addAll(fields, declaredFields);
    }
    populateFields(clazz.getSuperclass(), fields);
  }

  /**
   * Is service interface boolean.
   *
   * @param basePackage the base package
   * @param type        the type
   * @return the boolean
   */
  public static boolean isServiceInterface(String basePackage, Class type) {
    if (isTestClass(type)) {
      return true;
    }
    Set> subTypes = new Reflections(basePackage).getSubTypesOf(type);
    if (subTypes == null) {
      return false;
    }
    Iterator> iterator = subTypes.iterator();
    while (iterator.hasNext()) {
      if (isTestClass(iterator.next())) {
        iterator.remove();
      }
    }
    return subTypes.size() == 1;
  }

  /**
   * Gets instance fields.
   *
   * @param service the service
   * @return the instance fields
   */
  public Set getInstanceFields(Class service) {
    final Set instanceFields = new HashSet<>();
    if (isTestClass(service)) {
      return instanceFields;
    }
    Set allFields = new HashSet<>();
    populateFields(service, allFields);
    for (Field field : allFields) {
      if (Modifier.isFinal(field.getModifiers())) {
        continue;
      }
      if (field.isAnnotationPresent(IgnoredInstance.class)) {
        continue;
      }
      if (field.isAnnotationPresent(Autowired.class)) {
        continue;
      }
      if (field.isAnnotationPresent(Value.class)) {
        continue;
      }
      if (isServiceInterface(basePackage, field.getType())) {
        continue;
      }
      if (!isInstance(field)) {
        continue;
      }
      instanceFields.add(field);
    }
    return instanceFields;
  }

  /**
   * Hook to add more validations.
   *
   * @param field the field
   * @return the boolean
   */
  protected boolean isInstance(Field field) {
    return true;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy