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

org.stjs.generator.NamespaceUtil Maven / Gradle / Ivy

package org.stjs.generator;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

import org.stjs.javascript.annotation.Namespace;

public final class NamespaceUtil {

	private NamespaceUtil() {
		// nobody should extend this class
	}

	public static String resolveNamespace(Class clazz) {
		String ns = resolveNamespaceSimple(clazz);
		if (ns == null && clazz.getPackage() != null) {
			// the class is not annotated, let's see if its package is
			return resolvePackageNamespace(clazz.getPackage().getName(), clazz.getClassLoader());
		}
		return ns;
	}

	public static String resolveNamespace(String className, ClassLoader classLoader) {
		try {
			Class clazz = Class.forName(className, false, classLoader);
			return resolveNamespace(clazz);
		}
		catch (ClassNotFoundException cnfe) {
			throw new STJSRuntimeException(cnfe);
		}
	}

	public static String resolvePackageNamespace(String packageName, ClassLoader classLoader) {
		Package pack = getPackage(packageName, classLoader);
		if (pack != null) {
			String ns = getNamespaceAnnotationValue(pack, classLoader);
			if (ns != null) {
				return ns;
			}
		}

		// no annotation found on this package, let's check the parent
		int lastDotIndex = packageName.lastIndexOf('.');
		if (lastDotIndex < 0) {
			// there is no parent...
			return null;
		}

		return resolvePackageNamespace(packageName.substring(0, lastDotIndex), classLoader);
	}

	public static String resolveNamespaceSimple(String className, ClassLoader classLoader) {
		try {
			Class clazz = Class.forName(className, false, classLoader);
			return resolveNamespaceSimple(clazz);
		}
		catch (ClassNotFoundException cnfe) {
			throw new STJSRuntimeException(cnfe);
		}
	}

	public static String resolveNamespaceSimple(Class clazz) {
		String ns = getNamespaceAnnotationValue(clazz, clazz.getClassLoader());
		if (ns != null) {
			return ns;
		}

		// Annotation not found, maybe we have a namespace in the corresponding.stjs file.
		return getNamespacePropertyValue(clazz);
	}

	private static String getNamespacePropertyValue(Class clazz) {
		if (clazz.getClassLoader() == null) {
			// the class was loaded by the system classloader.
			// There is nothing in the system ClassLoader that could possibly have been annotated with
			// @Namespace
			return null;
		}

		String propertiesPath = clazz.getName().replace(".", "/") + ".stjs";
		InputStream in = clazz.getClassLoader().getResourceAsStream(propertiesPath);
		if (in == null) {
			// the properties file does not exist
			return null;
		}

		try {
			Properties props = new Properties();
			props.load(in);
			return props.getProperty(STJSClass.JS_NAMESPACE);
		}
		catch (IOException e) {
			// Properties exists, but we couldn't read it for some reason.
			throw new STJSRuntimeException(e);
		}
	}

	private static String getNamespaceAnnotationValue(AnnotatedElement element, ClassLoader classLoader) {
		if (classLoader == null) {
			// If the classLoader is null, then the element has been loaded by the system ClassLoader.
			// There is nothing in the system ClassLoader that could possibly have been annotated with
			// @Namespace
			return null;
		}

		try {
			Annotation annotation = element.getAnnotation(getNamespaceClass(classLoader));
			if (annotation == null) {
				return null;
			}
			return (String) annotation.getClass().getMethod("value").invoke(annotation);
		}
		catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
			throw new STJSRuntimeException(e);
		}
	}

	/**
	 * Returns an instance of the @Namespace annotation class that is loaded from the specified ClassLoader.
	 * In most cases, the current thread runs within the maven plugin which uses a different ClassLoader than
	 * the one that contains the classpath of the project that is being compile. This method is useful to make
	 * sure that calling Class.getAnnotation or Package.getAnnotation returns the expected result.
	 */
	@SuppressWarnings("unchecked")
	private static Class getNamespaceClass(ClassLoader classLoader) throws ClassNotFoundException {
		return (Class) Class.forName(Namespace.class.getName(), true, classLoader);
	}

	private static Package getPackage(String packageName, ClassLoader classLoader) {
		// try to load the package info class to force the package loading
		Class clazz;
		try {
			clazz = Class.forName(packageName + ".package-info", true, classLoader);
		}
		catch (ClassNotFoundException e) {
			// no class;
			return null;
		}

		return clazz.getPackage();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy