
org.pustefixframework.maven.plugins.Reflection Maven / Gradle / Ivy
The newest version!
/*
* This file is part of Pustefix.
*
* Pustefix is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Pustefix is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Pustefix; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.pustefixframework.maven.plugins;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.w3c.dom.Document;
/**
* Utility methods used by the mojo.
*
* @author [email protected]
*/
public class Reflection {
public static Reflection create(MavenProject project) throws MojoExecutionException {
URL[] cp;
List artifacts;
StringBuilder classpath;
File file;
classpath = new StringBuilder();
try {
artifacts = extracted(project);
cp = new URL[artifacts.size() + 1];
file = new File(project.getBuild().getOutputDirectory());
cp[0] = file.toURI().toURL();
classpath.append(file);
for (int i = 1; i < cp.length; i++) {
file = artifacts.get(i - 1).getFile();
cp[i] = file.toURI().toURL();
classpath.append(':').append(file.getAbsolutePath());
}
} catch (MalformedURLException e) {
throw new MojoExecutionException("invalid url", e);
}
return new Reflection(new URLClassLoader(cp, Reflection.class.getClassLoader()), classpath.toString());
}
@SuppressWarnings("unchecked")
private static List extracted(MavenProject project) {
return project.getCompileArtifacts();
}
private final URLClassLoader loader;
private final String classpath;
public Reflection(URLClassLoader loader, String classpath) {
this.loader = loader;
this.classpath = classpath;
}
public String getClasspath() {
return classpath;
}
public Class> clazz(String name) throws MojoExecutionException {
try {
return loader.loadClass(name);
} catch (ClassNotFoundException e) {
throw new MojoExecutionException(name + ": class not found in classpath " + toString(loader.getURLs()));
}
}
private static String toString(URL[] urls) {
StringBuilder builder;
builder = new StringBuilder();
for (URL url : urls) {
if (builder.length() > 0) {
builder.append(':');
}
builder.append(url.toString());
}
return builder.toString();
}
/**
* Returns the default target namespace of a class as defined in the JAX-WS
* specification. The namespace is derived from the package of the class
* using {@link #getTargetNamespace(Package)}.
*
* @param clazz the Java class
* @return the default target namespace
*/
public static String getTargetNamespace(Class> clazz) {
if (clazz == null) throw new IllegalArgumentException("Class argument must not be null");
return getTargetNamespace(clazz.getPackage());
}
/**
* Returns the default target namespace of a package as defined in the
* JAX-WS specification.
*
* @param pkg the Java package
* @return the default target namespace
*/
public static String getTargetNamespace(Package pkg) {
if (pkg == null) throw new IllegalArgumentException("Class has no package information");
StringBuilder sb = new StringBuilder();
sb.append("http://");
String name = pkg.getName();
String[] pkgs = name.split("\\.");
for (int i = pkgs.length - 1; i > -1; i--) {
sb.append(pkgs[i]);
if (i > 0) sb.append(".");
}
sb.append("/");
return sb.toString();
}
/**
* Checks if the webservice interface has been modified since the last
* modification of a reference file.
*/
public boolean checkInterfaceChange(String className, File buildDir, File refFile) throws MojoExecutionException {
if(className == null) return false;
Class> clazz = clazz(className);
if (!clazz.isInterface()) throw new MojoExecutionException("Web service interface class '" + className + "' doesn't define an interface type.");
// Check if interface or dependant interfaces changed
boolean changed = checkTypeChange(clazz, buildDir, refFile);
if (changed) return true;
// Check if method parameter or return type classes changed
Method[] meths = clazz.getMethods();
for (int i = 0; i < meths.length; i++) {
Class> ret = meths[i].getReturnType();
changed = checkTypeChange(ret, buildDir, refFile);
if (changed) return true;
Class>[] pars = meths[i].getParameterTypes();
for (int j = 0; j < pars.length; j++) {
changed = checkTypeChange(pars[j], buildDir, refFile);
if (changed) return true;
}
}
return false;
}
/**
* Checks if a class has been modified since the last modification of a
* reference file.
* @throws MojoExecutionException
*/
public boolean checkTypeChange(Class> clazz, File buildDir, File refFile) throws MojoExecutionException {
if (!clazz.isPrimitive()) {
ClassLoader cl = clazz.getClassLoader();
if (cl == loader) {
if (clazz.isArray()) return checkTypeChange(getArrayType(clazz), buildDir, refFile);
String path = clazz.getName().replace('.', File.separatorChar) + ".class";
File file = new File(buildDir, path);
long lastMod = Long.MAX_VALUE;
if (!file.exists()) {
URL url = cl.getResource(path);
if (url == null) throw new MojoExecutionException("Can't get URL for webservice class '" + clazz.getName() + "' from jar file.");
else {
try {
JarURLConnection con = (JarURLConnection) url.openConnection();
lastMod = con.getJarEntry().getTime();
} catch (IOException x) {
throw new MojoExecutionException("Can't get modification time for webservice class '" + clazz.getName() + "' from jar file.");
}
}
} else {
lastMod = file.lastModified();
}
if (refFile.lastModified() < lastMod) return true;
if (clazz.isInterface()) {
Class>[] itfs = clazz.getInterfaces();
for (int i = 0; i < itfs.length; i++) {
boolean changed = checkTypeChange(itfs[i], buildDir, refFile);
if (changed) return true;
}
} else {
Class> sup = clazz.getSuperclass();
boolean changed = checkTypeChange(sup, buildDir, refFile);
if (changed) return true;
}
}
}
return false;
}
/**
* Get the root component type of an array (with arbitrary dimensions)
*/
public static Class> getArrayType(Class> clazz) {
if (clazz.isArray()) return getArrayType(clazz.getComponentType());
else return clazz;
}
/**
* Checks if the method's return or parameter types contain an interface
* (which isn't supported by JAXB)
*/
public static boolean hasInterfaceType(Method method) {
if (method.getReturnType().isInterface()) return true;
Class>[] types = method.getParameterTypes();
for (Class> type : types) {
if (isInterfaceType(type)) return true;
}
return false;
}
/**
* Checks if class is an interface or an array of an interface type
*/
private static boolean isInterfaceType(Class> clazz) {
if(clazz.isArray()) return isInterfaceType(clazz.getComponentType());
return clazz.isInterface();
}
/**
* Creates string representation of Java type (in source code form)
*/
public static String getTypeString(Type type) {
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
Type rawType = paramType.getRawType();
String str = getTypeString(rawType);
Type[] typeArgs = paramType.getActualTypeArguments();
str += "<";
for (int i = 0; i < typeArgs.length; i++) {
if (i > 0) str += ",";
str += getTypeString(typeArgs[i]);
}
str += ">";
return str;
} else if (type instanceof GenericArrayType) {
GenericArrayType arrayType = (GenericArrayType) type;
Type compType = arrayType.getGenericComponentType();
return getTypeString(compType) + "[]";
} else if (type instanceof WildcardType) {
WildcardType wildType = (WildcardType) type;
Type[] lowerTypes = wildType.getLowerBounds();
String str = "";
if (lowerTypes.length == 1) {
str += "? super ";
str += getTypeString(lowerTypes[0]);
} else if (lowerTypes.length > 1) throw new RuntimeException("Multiple lower bounds aren't supported");
Type[] upperTypes = wildType.getUpperBounds();
if (upperTypes.length == 1) {
if (upperTypes[0] == Object.class) str += "?";
else {
if (lowerTypes.length > 0) throw new RuntimeException("Lower bounds with upper bounds aren't supported");
str += "? extends ";
str += getTypeString(upperTypes[0]);
}
} else if (upperTypes.length > 1) throw new RuntimeException("Multiple upper bounds aren't supported");
return str;
} else if (type instanceof TypeVariable) {
throw new RuntimeException("Not supported");
} else {
Class> clazz = (Class>) type;
return clazz.getCanonicalName();
}
}
/**
* Reads Document from a XML file.
*/
public static Document loadDoc(File file) throws MojoExecutionException {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document doc = docBuilder.parse(file);
return doc;
} catch (Exception x) {
throw new MojoExecutionException("Can't load XML document from file " + file.getAbsolutePath(), x);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy