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

com.softicar.platform.common.code.classpath.metadata.ClasspathFilesMetadata Maven / Gradle / Ivy

Go to download

The SoftiCAR Platform is a lightweight, Java-based library to create interactive business web applications.

There is a newer version: 50.0.0
Show newest version
package com.softicar.platform.common.code.classpath.metadata;

import com.softicar.platform.common.core.exceptions.SofticarDeveloperException;
import com.softicar.platform.common.core.exceptions.SofticarIOException;
import com.softicar.platform.common.core.java.classpath.JavaClasspath;
import com.softicar.platform.common.io.classfile.ClassFile;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * Identify classes that annotate, implement, or extend certain classes or
 * interfaces
 */
public class ClasspathFilesMetadata implements IClasspathFilesMetadata {

	private static final ClasspathFilesMetadata INSTANCE = new ClasspathFilesMetadata();
	private static final String MODULE_INFO_CLASS_FILENAME = "module-info.class";
	private final Map> extendingClasses;
	private final Map> implementingClasses;
	private final Map> annotatedClasses;

	private ClasspathFilesMetadata() {

		extendingClasses = new TreeMap<>();
		implementingClasses = new TreeMap<>();
		annotatedClasses = new TreeMap<>();

		for (var root: JavaClasspath.getInstance().getPayloadRoots()) {
			for (var file: root.getClassFiles()) {
				if (!file.getName().equals(MODULE_INFO_CLASS_FILENAME)) {
					try (InputStream inputStream = file.getInputStream()) {
						ClassFile classFile = new ClassFile(inputStream);

						parseMetadata(extendingClasses, classFile, Collections.singleton(classFile.getSuperClass()));
						parseMetadata(implementingClasses, classFile, classFile.getInterfaces());
						parseMetadata(annotatedClasses, classFile, parseAnnotationsFrom(classFile));
					} catch (IOException exception) {
						throw new SofticarIOException(exception);
					}
				}
			}
		}
	}

	public static ClasspathFilesMetadata getInstance() {

		return INSTANCE;
	}

	@Override
	public Collection> getDirectlyImplementingClasses(Class interfaceClass) {

		return getClasses(interfaceClass, implementingClasses);
	}

	@Override
	public Collection> getDirectlyExtendingClasses(Class baseClass) {

		return getClasses(baseClass, extendingClasses);
	}

	@Override
	public Collection> getDirectlyAnnotatedClasses(Class annotation) {

		return getClasses(annotation, annotatedClasses);
	}

	@Override
	public Collection> getTransitivelyImplementingClasses(Class interfaces) {

		return new TransitivelyImplementingClassesFinder(this).findAll(interfaces);
	}

	@Override
	public Collection> getTransitivelyExtendingClasses(Class baseClass) {

		return new TransitivelyExtendingClassesFinder(this).findAll(baseClass);
	}

	// ------------------------------ private ------------------------------ //

	private Collection> getClasses(Class interfaceClass, Map> classesMap) {

		return classesMap//
			.getOrDefault(interfaceClass.getName(), Collections.emptySet())
			.stream()
			.map(this::getClassByName)
			.collect(Collectors.toList());
	}

	private Class getClassByName(String className) {

		try {
			return Class.forName(className);
		} catch (ClassNotFoundException exception) {
			throw new SofticarDeveloperException(exception);
		}
	}

	private void parseMetadata(Map> classMetadataMap, ClassFile classFile, Collection metadataRaw) {

		for (String classname: metadataRaw) {
			classMetadataMap//
				.computeIfAbsent(classname.replace("/", "."), dummy -> new TreeSet<>())
				.add(classFile.getThisClass().replace("/", "."));
		}
	}

	private Collection parseAnnotationsFrom(ClassFile classFile) {

		TreeSet annotations = new TreeSet<>();
		classFile //
			.getAttributes()
			.stream()
			.filter(
				filteredAttribute -> filteredAttribute.getName().equals("RuntimeVisibleAnnotations")
						|| filteredAttribute.getName().equals("RuntimeInvisibleAnnotations"))
			.forEach(foundAttribute -> annotations.addAll(foundAttribute.parseAnnotationsFrom()));

		return annotations;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy