Added intellij support. Compiled as java6
This commit is contained in:
parent
6ffa6711bb
commit
d3a931ab36
@ -7,13 +7,13 @@
|
|||||||
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
|
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
|
||||||
</src_description>
|
</src_description>
|
||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="jdk" jdkName="1.6" jdkType="JavaSDK" />
|
||||||
<orderEntry type="module" module-name="Dorkbox-Util" />
|
<orderEntry type="module" module-name="Dorkbox-Util" />
|
||||||
<orderEntry type="library" name="logging slf4j-api (1.7.5)" level="application" />
|
<orderEntry type="library" name="logging slf4j-api (1.7.5)" level="application" />
|
||||||
<orderEntry type="library" name="bouncyCastle bcpkix-jdk15on (1.51)" level="application" />
|
<orderEntry type="library" name="bouncyCastle bcpkix-jdk15on (1.51)" level="application" />
|
||||||
|
@ -24,52 +24,61 @@ import java.lang.reflect.Method;
|
|||||||
/**
|
/**
|
||||||
* for specifying the default report methods, without constantly creating new objects
|
* for specifying the default report methods, without constantly creating new objects
|
||||||
*/
|
*/
|
||||||
public class AnnotationDefaults {
|
public
|
||||||
|
class AnnotationDefaults {
|
||||||
public static final ReporterFunction<String> getTypeName = new ReporterFunction<String>() {
|
public static final ReporterFunction<String> getTypeName = new ReporterFunction<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String report(Cursor cursor) {
|
public
|
||||||
|
String report(Cursor cursor) {
|
||||||
return cursor.getTypeName();
|
return cursor.getTypeName();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<Class<? extends Annotation>> getAnnotationType = new ReporterFunction<Class<? extends Annotation>>() {
|
public static final ReporterFunction<Class<? extends Annotation>> getAnnotationType = new ReporterFunction<Class<? extends Annotation>>() {
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends Annotation> report(Cursor cursor) {
|
public
|
||||||
|
Class<? extends Annotation> report(Cursor cursor) {
|
||||||
return cursor.getAnnotationType();
|
return cursor.getAnnotationType();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<ElementType> getElementType = new ReporterFunction<ElementType>() {
|
public static final ReporterFunction<ElementType> getElementType = new ReporterFunction<ElementType>() {
|
||||||
@Override
|
@Override
|
||||||
public ElementType report(Cursor cursor) {
|
public
|
||||||
|
ElementType report(Cursor cursor) {
|
||||||
return cursor.getElementType();
|
return cursor.getElementType();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<String> getMemberName = new ReporterFunction<String>() {
|
public static final ReporterFunction<String> getMemberName = new ReporterFunction<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String report(Cursor cursor) {
|
public
|
||||||
|
String report(Cursor cursor) {
|
||||||
return cursor.getMemberName();
|
return cursor.getMemberName();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<Class<?>> getType = new ReporterFunction<Class<?>>() {
|
public static final ReporterFunction<Class<?>> getType = new ReporterFunction<Class<?>>() {
|
||||||
@Override
|
@Override
|
||||||
public Class<?> report(Cursor cursor) {
|
public
|
||||||
|
Class<?> report(Cursor cursor) {
|
||||||
return cursor.getType();
|
return cursor.getType();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<Constructor<?>> getConstructor = new ReporterFunction<Constructor<?>>() {
|
public static final ReporterFunction<Constructor<?>> getConstructor = new ReporterFunction<Constructor<?>>() {
|
||||||
@Override
|
@Override
|
||||||
public Constructor<?> report(Cursor cursor) {
|
public
|
||||||
|
Constructor<?> report(Cursor cursor) {
|
||||||
return cursor.getConstructor();
|
return cursor.getConstructor();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<Field> getField = new ReporterFunction<Field>() {
|
public static final ReporterFunction<Field> getField = new ReporterFunction<Field>() {
|
||||||
@Override
|
@Override
|
||||||
public Field report(Cursor cursor) {
|
public
|
||||||
|
Field report(Cursor cursor) {
|
||||||
return cursor.getField();
|
return cursor.getField();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public static final ReporterFunction<Method> getMethod = new ReporterFunction<Method>() {
|
public static final ReporterFunction<Method> getMethod = new ReporterFunction<Method>() {
|
||||||
@Override
|
@Override
|
||||||
public Method report(Cursor cursor) {
|
public
|
||||||
|
Method report(Cursor cursor) {
|
||||||
return cursor.getMethod();
|
return cursor.getMethod();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,11 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.annotation;
|
package dorkbox.util.annotation;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FilenameFilter;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
@ -35,29 +33,18 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.JarURLConnection;
|
import java.net.JarURLConnection;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code AnnotationDetector} reads Java Class Files ("*.class") and reports the
|
* {@code AnnotationDetector} reads Java Class Files ("*.class") and reports the
|
||||||
* found annotations via a simple, developer friendly API.
|
* found annotations via a simple, developer friendly API.
|
||||||
* <p>
|
* <p/>
|
||||||
* A Java Class File consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit
|
* A Java Class File consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit
|
||||||
* quantities are constructed by reading in two, four, and eight consecutive 8-bit
|
* quantities are constructed by reading in two, four, and eight consecutive 8-bit
|
||||||
* bytes, respectively. Multi byte data items are always stored in big-endian order,
|
* bytes, respectively. Multi byte data items are always stored in big-endian order,
|
||||||
* where the high bytes come first. In the Java platforms, this format is
|
* where the high bytes come first. In the Java platforms, this format is
|
||||||
* supported by interfaces {@link java.io.DataInput} and {@link java.io.DataOutput}.
|
* supported by interfaces {@link java.io.DataInput} and {@link java.io.DataOutput}.
|
||||||
* <p>
|
* <p/>
|
||||||
* A class file consists of a single ClassFile structure:
|
* A class file consists of a single ClassFile structure:
|
||||||
* <pre>
|
* <pre>
|
||||||
* ClassFile {
|
* ClassFile {
|
||||||
@ -97,7 +84,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
* <li><a href="http://stackoverflow.com/questions/259140">scanning java annotations at
|
* <li><a href="http://stackoverflow.com/questions/259140">scanning java annotations at
|
||||||
* runtime</a>.
|
* runtime</a>.
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>
|
* <p/>
|
||||||
* Similar projects / libraries:
|
* Similar projects / libraries:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><a href="http://community.jboss.org/wiki/MCScanninglib">JBoss MC Scanning lib</a>;
|
* <li><a href="http://community.jboss.org/wiki/MCScanninglib">JBoss MC Scanning lib</a>;
|
||||||
@ -108,18 +95,19 @@ import org.slf4j.LoggerFactory;
|
|||||||
* Available from maven: {@code tv.cntt:annovention:1.2};
|
* Available from maven: {@code tv.cntt:annovention:1.2};
|
||||||
* <li>If using the Spring Framework, use {@code ClassPathScanningCandidateComponentProvider}
|
* <li>If using the Spring Framework, use {@code ClassPathScanningCandidateComponentProvider}
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>
|
* <p/>
|
||||||
* All above mentioned projects make use of a byte code manipulation library (like BCEL,
|
* All above mentioned projects make use of a byte code manipulation library (like BCEL,
|
||||||
* ASM or Javassist).
|
* ASM or Javassist).
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
public final class AnnotationDetector implements Builder, Cursor {
|
public final
|
||||||
|
class AnnotationDetector implements Builder, Cursor {
|
||||||
|
|
||||||
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AnnotationDetector.class);
|
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AnnotationDetector.class);
|
||||||
|
|
||||||
// Constant Pool type tags
|
// Constant Pool type ta gs
|
||||||
private static final int CP_UTF8 = 1;
|
private static final int CP_UTF8 = 1;
|
||||||
private static final int CP_INTEGER = 3;
|
private static final int CP_INTEGER = 3;
|
||||||
private static final int CP_FLOAT = 4;
|
private static final int CP_FLOAT = 4;
|
||||||
@ -180,18 +168,20 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
// "(Ljava/lang/String;II)I" String, int, int as arguments, return type int
|
// "(Ljava/lang/String;II)I" String, int, int as arguments, return type int
|
||||||
private String methodDescriptor;
|
private String methodDescriptor;
|
||||||
|
|
||||||
private AnnotationDetector(ClassLoader loader, final File[] filesOrDirectories, ClassIterator iterator, final String[] pkgNameFilter) {
|
private
|
||||||
|
AnnotationDetector(ClassLoader loader, final File[] filesOrDirectories, ClassIterator iterator, final String[] pkgNameFilter) {
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
if (iterator == null) {
|
if (iterator == null) {
|
||||||
this.cfIterator = new ClassFileIterator(filesOrDirectories, pkgNameFilter);
|
this.cfIterator = new ClassFileIterator(filesOrDirectories, pkgNameFilter);
|
||||||
|
|
||||||
if (filesOrDirectories.length == 0) {
|
if (filesOrDirectories.length == 0) {
|
||||||
LOG.warn("No files or directories to scan!");
|
LOG.warn("No files or directories to scan!");
|
||||||
} else if (LOG.isTraceEnabled()) {
|
|
||||||
LOG.trace("Files and root directories scanned:\n{}",
|
|
||||||
Arrays.toString(filesOrDirectories).replace(", ", "\n"));
|
|
||||||
}
|
}
|
||||||
} else {
|
else if (LOG.isTraceEnabled()) {
|
||||||
|
LOG.trace("Files and root directories scanned:\n{}", Arrays.toString(filesOrDirectories).replace(", ", "\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.cfIterator = iterator;
|
this.cfIterator = iterator;
|
||||||
|
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
@ -206,8 +196,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Only scan Class Files in the specified packages. If nothing is specified, all classes
|
* Only scan Class Files in the specified packages. If nothing is specified, all classes
|
||||||
* on the class path are scanned.
|
* on the class path are scanned.
|
||||||
*/
|
*/
|
||||||
public static Builder scanClassPath(final String... packageNames)
|
public static
|
||||||
throws IOException {
|
Builder scanClassPath(final String... packageNames) throws IOException {
|
||||||
|
|
||||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||||
return scanClassPath(loader, packageNames);
|
return scanClassPath(loader, packageNames);
|
||||||
@ -218,8 +208,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Only scan Class Files in the specified packages. If nothing is specified, all classes
|
* Only scan Class Files in the specified packages. If nothing is specified, all classes
|
||||||
* on the class path are scanned.
|
* on the class path are scanned.
|
||||||
*/
|
*/
|
||||||
public static Builder scanClassPath(ClassLoader loader, final String... packageNames)
|
public static
|
||||||
throws IOException {
|
Builder scanClassPath(ClassLoader loader, final String... packageNames) throws IOException {
|
||||||
|
|
||||||
final String[] pkgNameFilter;
|
final String[] pkgNameFilter;
|
||||||
|
|
||||||
@ -259,7 +249,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new AnnotationDetector(loader, null, new CustomClassloaderIterator(fileNames, packageNames), pkgNameFilter);
|
return new AnnotationDetector(loader, null, new CustomClassloaderIterator(fileNames, packageNames), pkgNameFilter);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
final Set<File> files = new HashSet<File>();
|
final Set<File> files = new HashSet<File>();
|
||||||
|
|
||||||
if (packageNames.length == 0) {
|
if (packageNames.length == 0) {
|
||||||
@ -268,7 +259,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
for (int i = 0; i < fileNames.length; ++i) {
|
for (int i = 0; i < fileNames.length; ++i) {
|
||||||
files.add(new File(fileNames[i]));
|
files.add(new File(fileNames[i]));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
pkgNameFilter = new String[packageNames.length];
|
pkgNameFilter = new String[packageNames.length];
|
||||||
for (int i = 0; i < pkgNameFilter.length; ++i) {
|
for (int i = 0; i < pkgNameFilter.length; ++i) {
|
||||||
pkgNameFilter[i] = packageNames[i].replace('.', '/');
|
pkgNameFilter[i] = packageNames[i].replace('.', '/');
|
||||||
@ -288,7 +280,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Factory method, starting point for the fluent interface.
|
* Factory method, starting point for the fluent interface.
|
||||||
* Scan all files specified by the classFileIterator.
|
* Scan all files specified by the classFileIterator.
|
||||||
*/
|
*/
|
||||||
public static Builder scan(ClassLoader loader, final ClassIterator iterator) {
|
public static
|
||||||
|
Builder scan(ClassLoader loader, final ClassIterator iterator) {
|
||||||
return new AnnotationDetector(loader, null, iterator, null);
|
return new AnnotationDetector(loader, null, iterator, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +289,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Factory method, starting point for the fluent interface.
|
* Factory method, starting point for the fluent interface.
|
||||||
* Scan all files in the specified jar files and directories.
|
* Scan all files in the specified jar files and directories.
|
||||||
*/
|
*/
|
||||||
public static Builder scanFiles(ClassLoader loader, final File... filesOrDirectories) {
|
public static
|
||||||
|
Builder scanFiles(ClassLoader loader, final File... filesOrDirectories) {
|
||||||
return new AnnotationDetector(loader, filesOrDirectories, null, null);
|
return new AnnotationDetector(loader, filesOrDirectories, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +298,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Factory method, starting point for the fluent interface.
|
* Factory method, starting point for the fluent interface.
|
||||||
* Scan all files in the specified jar files and directories.
|
* Scan all files in the specified jar files and directories.
|
||||||
*/
|
*/
|
||||||
public static Builder scanFiles(final File... filesOrDirectories) {
|
public static
|
||||||
|
Builder scanFiles(final File... filesOrDirectories) {
|
||||||
return new AnnotationDetector(Thread.currentThread().getContextClassLoader(), filesOrDirectories, null, null);
|
return new AnnotationDetector(Thread.currentThread().getContextClassLoader(), filesOrDirectories, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +307,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#forAnnotations(java.lang.Class...) }.
|
* See {@link Builder#forAnnotations(java.lang.Class...) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Builder forAnnotations(final Class<? extends Annotation> annotation) {
|
public
|
||||||
|
Builder forAnnotations(final Class<? extends Annotation> annotation) {
|
||||||
this.annotations = new HashMap<String, Class<? extends Annotation>>(1);
|
this.annotations = new HashMap<String, Class<? extends Annotation>>(1);
|
||||||
// map "raw" type names to Class object
|
// map "raw" type names to Class object
|
||||||
this.annotations.put("L" + annotation.getName().replace('.', '/') + ";", annotation);
|
this.annotations.put("L" + annotation.getName().replace('.', '/') + ";", annotation);
|
||||||
@ -324,7 +320,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Builder forAnnotations(final Class<? extends Annotation>... annotations) {
|
public
|
||||||
|
Builder forAnnotations(final Class<? extends Annotation>... annotations) {
|
||||||
this.annotations = new HashMap<String, Class<? extends Annotation>>(annotations.length);
|
this.annotations = new HashMap<String, Class<? extends Annotation>>(annotations.length);
|
||||||
// map "raw" type names to Class object
|
// map "raw" type names to Class object
|
||||||
for (int i = 0; i < annotations.length; ++i) {
|
for (int i = 0; i < annotations.length; ++i) {
|
||||||
@ -337,7 +334,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#on(java.lang.annotation.ElementType...) }.
|
* See {@link Builder#on(java.lang.annotation.ElementType...) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Builder on(final ElementType type) {
|
public
|
||||||
|
Builder on(final ElementType type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new IllegalArgumentException("At least one Element Type must be specified");
|
throw new IllegalArgumentException("At least one Element Type must be specified");
|
||||||
}
|
}
|
||||||
@ -359,7 +357,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#on(java.lang.annotation.ElementType...) }.
|
* See {@link Builder#on(java.lang.annotation.ElementType...) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Builder on(final ElementType... types) {
|
public
|
||||||
|
Builder on(final ElementType... types) {
|
||||||
if (types.length == 0) {
|
if (types.length == 0) {
|
||||||
throw new IllegalArgumentException("At least one Element Type must be specified");
|
throw new IllegalArgumentException("At least one Element Type must be specified");
|
||||||
}
|
}
|
||||||
@ -383,7 +382,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#filter(java.io.FilenameFilter) }.
|
* See {@link Builder#filter(java.io.FilenameFilter) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Builder filter(final FilenameFilter filter) {
|
public
|
||||||
|
Builder filter(final FilenameFilter filter) {
|
||||||
if (filter == null) {
|
if (filter == null) {
|
||||||
throw new NullPointerException("'filter' may not be null");
|
throw new NullPointerException("'filter' may not be null");
|
||||||
}
|
}
|
||||||
@ -395,7 +395,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#report(dorkbox.util.annotation.AnnotationDetector.Reporter) }.
|
* See {@link Builder#report(dorkbox.util.annotation.AnnotationDetector.Reporter) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void report(final Reporter reporter) throws IOException {
|
public
|
||||||
|
void report(final Reporter reporter) throws IOException {
|
||||||
this.reporter = reporter;
|
this.reporter = reporter;
|
||||||
detect(this.cfIterator);
|
detect(this.cfIterator);
|
||||||
}
|
}
|
||||||
@ -404,12 +405,14 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Builder#collect(dorkbox.util.annotation.AnnotationDetector.ReporterFunction) }.
|
* See {@link Builder#collect(dorkbox.util.annotation.AnnotationDetector.ReporterFunction) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> List<T> collect(final ReporterFunction<T> reporter) throws IOException {
|
public
|
||||||
|
<T> List<T> collect(final ReporterFunction<T> reporter) throws IOException {
|
||||||
final List<T> list = new ArrayList<T>();
|
final List<T> list = new ArrayList<T>();
|
||||||
this.reporter = new Reporter() {
|
this.reporter = new Reporter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void report(Cursor cursor) {
|
public
|
||||||
|
void report(Cursor cursor) {
|
||||||
list.add(reporter.report(cursor));
|
list.add(reporter.report(cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +425,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getTypeName() }.
|
* See {@link Cursor#getTypeName() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getTypeName() {
|
public
|
||||||
|
String getTypeName() {
|
||||||
return this.typeName.replace('/', '.');
|
return this.typeName.replace('/', '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +434,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getAnnotationType() }.
|
* See {@link Cursor#getAnnotationType() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends Annotation> getAnnotationType() {
|
public
|
||||||
|
Class<? extends Annotation> getAnnotationType() {
|
||||||
return this.annotationType;
|
return this.annotationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +443,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getElementType() }.
|
* See {@link Cursor#getElementType() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ElementType getElementType() {
|
public
|
||||||
|
ElementType getElementType() {
|
||||||
return this.elementType;
|
return this.elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +452,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getMemberName() }.
|
* See {@link Cursor#getMemberName() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getMemberName() {
|
public
|
||||||
|
String getMemberName() {
|
||||||
return this.memberName;
|
return this.memberName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +461,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getType() }.
|
* See {@link Cursor#getType() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getType() {
|
public
|
||||||
|
Class<?> getType() {
|
||||||
return loadClass(this.loader, getTypeName());
|
return loadClass(this.loader, getTypeName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,16 +470,15 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getField() }.
|
* See {@link Cursor#getField() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Field getField() {
|
public
|
||||||
|
Field getField() {
|
||||||
if (this.elementType != ElementType.FIELD) {
|
if (this.elementType != ElementType.FIELD) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("Illegal to call getField() when " + this.elementType + " is reported");
|
||||||
"Illegal to call getField() when " + this.elementType + " is reported");
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return getType().getDeclaredField(this.memberName);
|
return getType().getDeclaredField(this.memberName);
|
||||||
} catch (NoSuchFieldException ex) {
|
} catch (NoSuchFieldException ex) {
|
||||||
throw assertionError(
|
throw assertionError("Cannot find Field '%s' for type %s", this.memberName, getTypeName());
|
||||||
"Cannot find Field '%s' for type %s", this.memberName, getTypeName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,17 +486,16 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getConstructor() }.
|
* See {@link Cursor#getConstructor() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Constructor<?> getConstructor() {
|
public
|
||||||
|
Constructor<?> getConstructor() {
|
||||||
if (this.elementType != ElementType.CONSTRUCTOR) {
|
if (this.elementType != ElementType.CONSTRUCTOR) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("Illegal to call getMethod() when " + this.elementType + " is reported");
|
||||||
"Illegal to call getMethod() when " + this.elementType + " is reported");
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
|
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
|
||||||
return getType().getConstructor(parameterTypes);
|
return getType().getConstructor(parameterTypes);
|
||||||
} catch (NoSuchMethodException ex) {
|
} catch (NoSuchMethodException ex) {
|
||||||
throw assertionError(
|
throw assertionError("Cannot find Contructor '%s(...)' for type %s", this.memberName, getTypeName());
|
||||||
"Cannot find Contructor '%s(...)' for type %s", this.memberName, getTypeName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,17 +503,16 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getMethod() }.
|
* See {@link Cursor#getMethod() }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Method getMethod() {
|
public
|
||||||
|
Method getMethod() {
|
||||||
if (this.elementType != ElementType.METHOD) {
|
if (this.elementType != ElementType.METHOD) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("Illegal to call getMethod() when " + this.elementType + " is reported");
|
||||||
"Illegal to call getMethod() when " + this.elementType + " is reported");
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
|
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
|
||||||
return getType().getDeclaredMethod(this.memberName, parameterTypes);
|
return getType().getDeclaredMethod(this.memberName, parameterTypes);
|
||||||
} catch (NoSuchMethodException ex) {
|
} catch (NoSuchMethodException ex) {
|
||||||
throw assertionError(
|
throw assertionError("Cannot find Method '%s(...)' for type %s", this.memberName, getTypeName());
|
||||||
"Cannot find Method '%s(...)' for type %s", this.memberName, getTypeName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +520,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* See {@link Cursor#getAnnotation(java.lang.Class) }.
|
* See {@link Cursor#getAnnotation(java.lang.Class) }.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
|
public
|
||||||
|
<T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
|
||||||
if (!annotationClass.equals(this.annotationType)) {
|
if (!annotationClass.equals(this.annotationType)) {
|
||||||
throw new IllegalStateException("Illegal to call getAnnotation() when " +
|
throw new IllegalStateException("Illegal to call getAnnotation() when " +
|
||||||
this.annotationType.getName() + " is reported");
|
this.annotationType.getName() + " is reported");
|
||||||
@ -539,8 +545,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
|
|
||||||
// private
|
// private
|
||||||
|
|
||||||
private static void addFiles(ClassLoader loader, String resourceName, Set<File> files)
|
private static
|
||||||
throws IOException {
|
void addFiles(ClassLoader loader, String resourceName, Set<File> files) throws IOException {
|
||||||
|
|
||||||
final Enumeration<URL> resourceEnum = loader.getResources(resourceName);
|
final Enumeration<URL> resourceEnum = loader.getResources(resourceName);
|
||||||
while (resourceEnum.hasMoreElements()) {
|
while (resourceEnum.hasMoreElements()) {
|
||||||
@ -557,7 +563,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
final File dir = toFile(url);
|
final File dir = toFile(url);
|
||||||
if (dir.isDirectory()) {
|
if (dir.isDirectory()) {
|
||||||
files.add(dir);
|
files.add(dir);
|
||||||
} else if (isVfs) {
|
}
|
||||||
|
else if (isVfs) {
|
||||||
//Jar file via JBoss VFS protocol - strip package name
|
//Jar file via JBoss VFS protocol - strip package name
|
||||||
String jarPath = dir.getPath();
|
String jarPath = dir.getPath();
|
||||||
final int idx = jarPath.indexOf(".jar");
|
final int idx = jarPath.indexOf(".jar");
|
||||||
@ -568,23 +575,26 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
files.add(jarFile);
|
files.add(jarFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
throw assertionError("Not a recognized file URL: %s", url);
|
throw assertionError("Not a recognized file URL: %s", url);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Resource in Jar File
|
// Resource in Jar File
|
||||||
final File jarFile =
|
final File jarFile = toFile(((JarURLConnection) url.openConnection()).getJarFileURL());
|
||||||
toFile(((JarURLConnection)url.openConnection()).getJarFileURL());
|
|
||||||
if (jarFile.isFile()) {
|
if (jarFile.isFile()) {
|
||||||
files.add(jarFile);
|
files.add(jarFile);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
throw assertionError("Not a File: %s", jarFile);
|
throw assertionError("Not a File: %s", jarFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File toFile(final URL url) throws IOException {
|
private static
|
||||||
|
File toFile(final URL url) throws IOException {
|
||||||
// only correct way to convert the URL to a File object, also see issue #16
|
// only correct way to convert the URL to a File object, also see issue #16
|
||||||
// Do not use URLDecoder
|
// Do not use URLDecoder
|
||||||
try {
|
try {
|
||||||
@ -594,7 +604,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void detect(final ClassIterator iterator) throws IOException {
|
private
|
||||||
|
void detect(final ClassIterator iterator) throws IOException {
|
||||||
InputStream stream;
|
InputStream stream;
|
||||||
boolean mustEndInClass = iterator instanceof ClassFileIterator;
|
boolean mustEndInClass = iterator instanceof ClassFileIterator;
|
||||||
while ((stream = iterator.next(this.filter)) != null) {
|
while ((stream = iterator.next(this.filter)) != null) {
|
||||||
@ -620,14 +631,16 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasCafebabe(final ClassFileBuffer buffer) throws IOException {
|
private
|
||||||
|
boolean hasCafebabe(final ClassFileBuffer buffer) throws IOException {
|
||||||
return buffer.size() > 4 && buffer.readInt() == 0xCAFEBABE;
|
return buffer.size() > 4 && buffer.readInt() == 0xCAFEBABE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect the given (Java) class file in streaming mode.
|
* Inspect the given (Java) class file in streaming mode.
|
||||||
*/
|
*/
|
||||||
private void read(final DataInput di) throws IOException {
|
private
|
||||||
|
void read(final DataInput di) throws IOException {
|
||||||
readVersion(di);
|
readVersion(di);
|
||||||
readConstantPoolEntries(di);
|
readConstantPoolEntries(di);
|
||||||
readAccessFlags(di);
|
readAccessFlags(di);
|
||||||
@ -639,18 +652,21 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
readAttributes(di, ElementType.TYPE);
|
readAttributes(di, ElementType.TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readVersion(final DataInput di) throws IOException {
|
private
|
||||||
|
void readVersion(final DataInput di) throws IOException {
|
||||||
// sequence: minor version, major version (argument_index is 1-based)
|
// sequence: minor version, major version (argument_index is 1-based)
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
int minor = di.readUnsignedShort();
|
int minor = di.readUnsignedShort();
|
||||||
int maj = di.readUnsignedShort();
|
int maj = di.readUnsignedShort();
|
||||||
LOG.trace("Java Class version {}.{}", maj, minor);
|
LOG.trace("Java Class version {}.{}", maj, minor);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
di.skipBytes(4);
|
di.skipBytes(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readConstantPoolEntries(final DataInput di) throws IOException {
|
private
|
||||||
|
void readConstantPoolEntries(final DataInput di) throws IOException {
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
this.constantPool = new Object[count];
|
this.constantPool = new Object[count];
|
||||||
for (int i = 1; i < count; ++i) {
|
for (int i = 1; i < count; ++i) {
|
||||||
@ -664,8 +680,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
/**
|
/**
|
||||||
* Return {@code true} if a double slot is read (in case of Double or Long constant).
|
* Return {@code true} if a double slot is read (in case of Double or Long constant).
|
||||||
*/
|
*/
|
||||||
private boolean readConstantPoolEntry(final DataInput di, final int index)
|
private
|
||||||
throws IOException {
|
boolean readConstantPoolEntry(final DataInput di, final int index) throws IOException {
|
||||||
|
|
||||||
final int tag = di.readUnsignedByte();
|
final int tag = di.readUnsignedByte();
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
@ -697,29 +713,33 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
this.constantPool[index] = di.readUnsignedShort();
|
this.constantPool[index] = di.readUnsignedShort();
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
throw new ClassFormatError(
|
throw new ClassFormatError("Unkown tag value for constant pool entry: " + tag);
|
||||||
"Unkown tag value for constant pool entry: " + tag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAccessFlags(final DataInput di) throws IOException {
|
private
|
||||||
|
void readAccessFlags(final DataInput di) throws IOException {
|
||||||
di.skipBytes(2); // u2
|
di.skipBytes(2); // u2
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readThisClass(final DataInput di) throws IOException {
|
private
|
||||||
|
void readThisClass(final DataInput di) throws IOException {
|
||||||
this.typeName = resolveUtf8(di);
|
this.typeName = resolveUtf8(di);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readSuperClass(final DataInput di) throws IOException {
|
private
|
||||||
|
void readSuperClass(final DataInput di) throws IOException {
|
||||||
di.skipBytes(2); // u2
|
di.skipBytes(2); // u2
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readInterfaces(final DataInput di) throws IOException {
|
private
|
||||||
|
void readInterfaces(final DataInput di) throws IOException {
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
di.skipBytes(count * 2); // count * u2
|
di.skipBytes(count * 2); // count * u2
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readFields(final DataInput di) throws IOException {
|
private
|
||||||
|
void readFields(final DataInput di) throws IOException {
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
readAccessFlags(di);
|
readAccessFlags(di);
|
||||||
@ -732,7 +752,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readMethods(final DataInput di) throws IOException {
|
private
|
||||||
|
void readMethods(final DataInput di) throws IOException {
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
readAccessFlags(di);
|
readAccessFlags(di);
|
||||||
@ -743,28 +764,28 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAttributes(final DataInput di, final ElementType reporterType)
|
private
|
||||||
throws IOException {
|
void readAttributes(final DataInput di, final ElementType reporterType) throws IOException {
|
||||||
|
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
final String name = resolveUtf8(di);
|
final String name = resolveUtf8(di);
|
||||||
// in bytes, use this to skip the attribute info block
|
// in bytes, use this to skip the attribute info block
|
||||||
final int length = di.readInt();
|
final int length = di.readInt();
|
||||||
if (this.elementTypes.contains(reporterType) &&
|
if (this.elementTypes.contains(reporterType) && ("RuntimeVisibleAnnotations".equals(name) ||
|
||||||
("RuntimeVisibleAnnotations".equals(name) ||
|
|
||||||
"RuntimeInvisibleAnnotations".equals(name))) {
|
"RuntimeInvisibleAnnotations".equals(name))) {
|
||||||
LOG.trace("Attribute: {}", name);
|
LOG.trace("Attribute: {}", name);
|
||||||
readAnnotations(di, reporterType);
|
readAnnotations(di, reporterType);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
LOG.trace("Attribute: {} (ignored)", name);
|
LOG.trace("Attribute: {} (ignored)", name);
|
||||||
di.skipBytes(length);
|
di.skipBytes(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAnnotations(final DataInput di, final ElementType elementType)
|
private
|
||||||
throws IOException {
|
void readAnnotations(final DataInput di, final ElementType elementType) throws IOException {
|
||||||
|
|
||||||
// the number of Runtime(In)VisibleAnnotations
|
// the number of Runtime(In)VisibleAnnotations
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
@ -775,21 +796,23 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
LOG.trace("Annotation: {} (ignored)", rawTypeName);
|
LOG.trace("Annotation: {} (ignored)", rawTypeName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LOG.trace("Annotation: ''{}'' on type ''{}'', member ''{}'' (reported)",
|
LOG.trace("Annotation: ''{}'' on type ''{}'', member ''{}'' (reported)", this.annotationType.getName(), getTypeName(),
|
||||||
this.annotationType.getName(), getTypeName(), getMemberName());
|
getMemberName());
|
||||||
this.elementType = elementType;
|
this.elementType = elementType;
|
||||||
this.reporter.report(this);
|
this.reporter.report(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readAnnotation(final DataInput di) throws IOException {
|
private
|
||||||
|
String readAnnotation(final DataInput di) throws IOException {
|
||||||
final String rawTypeName = resolveUtf8(di);
|
final String rawTypeName = resolveUtf8(di);
|
||||||
// num_element_value_pairs
|
// num_element_value_pairs
|
||||||
final int count = di.readUnsignedShort();
|
final int count = di.readUnsignedShort();
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
LOG.trace("Anntotation Element: {}", resolveUtf8(di));
|
LOG.trace("Anntotation Element: {}", resolveUtf8(di));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
di.skipBytes(2);
|
di.skipBytes(2);
|
||||||
}
|
}
|
||||||
readAnnotationElementValue(di);
|
readAnnotationElementValue(di);
|
||||||
@ -797,7 +820,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
return rawTypeName;
|
return rawTypeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAnnotationElementValue(final DataInput di) throws IOException {
|
private
|
||||||
|
void readAnnotationElementValue(final DataInput di) throws IOException {
|
||||||
final int tag = di.readUnsignedByte();
|
final int tag = di.readUnsignedByte();
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case BYTE:
|
case BYTE:
|
||||||
@ -827,8 +851,7 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ClassFormatError("Not a valid annotation element type tag: 0x" +
|
throw new ClassFormatError("Not a valid annotation element type tag: 0x" + Integer.toHexString(tag));
|
||||||
Integer.toHexString(tag));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,14 +859,16 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
* Look up the String value, identified by the u2 index value from constant pool
|
* Look up the String value, identified by the u2 index value from constant pool
|
||||||
* (direct or indirect).
|
* (direct or indirect).
|
||||||
*/
|
*/
|
||||||
private String resolveUtf8(final DataInput di) throws IOException {
|
private
|
||||||
|
String resolveUtf8(final DataInput di) throws IOException {
|
||||||
final int index = di.readUnsignedShort();
|
final int index = di.readUnsignedShort();
|
||||||
final Object value = this.constantPool[index];
|
final Object value = this.constantPool[index];
|
||||||
final String s;
|
final String s;
|
||||||
if (value instanceof Integer) {
|
if (value instanceof Integer) {
|
||||||
s = (String)this.constantPool[(Integer)value];
|
s = (String) this.constantPool[(Integer) value];
|
||||||
} else {
|
}
|
||||||
s = (String)value;
|
else {
|
||||||
|
s = (String) value;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -854,7 +879,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
*/
|
*/
|
||||||
// incorrect detection of dereferencing possible null pointer
|
// incorrect detection of dereferencing possible null pointer
|
||||||
// TODO: https://github.com/checkstyle/checkstyle/issues/14 fixed in 5.8?
|
// TODO: https://github.com/checkstyle/checkstyle/issues/14 fixed in 5.8?
|
||||||
private Class<?>[] parseArguments(final String descriptor) {
|
private
|
||||||
|
Class<?>[] parseArguments(final String descriptor) {
|
||||||
final int n = descriptor.length();
|
final int n = descriptor.length();
|
||||||
// "minimal" descriptor: no arguments: "()V", first character is always '('
|
// "minimal" descriptor: no arguments: "()V", first character is always '('
|
||||||
if (n < 3 || descriptor.charAt(0) != '(') {
|
if (n < 3 || descriptor.charAt(0) != '(') {
|
||||||
@ -866,7 +892,8 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
if (c == ')') {
|
if (c == ')') {
|
||||||
return new Class<?>[0];
|
return new Class<?>[0];
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
args = new LinkedList<Class<?>>();
|
args = new LinkedList<Class<?>>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -929,25 +956,26 @@ public final class AnnotationDetector implements Builder, Cursor {
|
|||||||
/**
|
/**
|
||||||
* Load the class, but do not initialize it.
|
* Load the class, but do not initialize it.
|
||||||
*/
|
*/
|
||||||
private static Class<?> loadClass(ClassLoader loader, final String rawClassName) {
|
private static
|
||||||
|
Class<?> loadClass(ClassLoader loader, final String rawClassName) {
|
||||||
final String typeName = rawClassName.replace('/', '.');
|
final String typeName = rawClassName.replace('/', '.');
|
||||||
try {
|
try {
|
||||||
return Class.forName(typeName, false, loader);
|
return Class.forName(typeName, false, loader);
|
||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
throw assertionError(
|
throw assertionError("Cannot load type '%s', scanned file not on class path? (%s)", typeName, ex);
|
||||||
"Cannot load type '%s', scanned file not on class path? (%s)", typeName, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method descriptor must always be parseable, so if not an AssertionError is thrown.
|
* The method descriptor must always be parseable, so if not an AssertionError is thrown.
|
||||||
*/
|
*/
|
||||||
private static AssertionError unparseable(final String descriptor, final String cause) {
|
private static
|
||||||
return assertionError(
|
AssertionError unparseable(final String descriptor, final String cause) {
|
||||||
"Unparseble method descriptor: '%s' (cause: %s)", descriptor, cause);
|
return assertionError("Unparseble method descriptor: '%s' (cause: %s)", descriptor, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AssertionError assertionError(String message, Object... args) {
|
private static
|
||||||
|
AssertionError assertionError(String message, Object... args) {
|
||||||
return new AssertionError(String.format(message, args));
|
return new AssertionError(String.format(message, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@ import java.util.List;
|
|||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.1.0
|
* @since annotation-detector 3.1.0
|
||||||
*/
|
*/
|
||||||
public interface Builder {
|
public
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the annotation types to report.
|
* Specify the annotation types to report.
|
||||||
@ -51,7 +52,7 @@ public interface Builder {
|
|||||||
/**
|
/**
|
||||||
* Specify the Element Types to scan. If this method is not called,
|
* Specify the Element Types to scan. If this method is not called,
|
||||||
* {@link ElementType#TYPE} is used as default.
|
* {@link ElementType#TYPE} is used as default.
|
||||||
* <p>
|
* <p/>
|
||||||
* Valid types are:
|
* Valid types are:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link ElementType#TYPE}
|
* <li>{@link ElementType#TYPE}
|
||||||
@ -66,7 +67,7 @@ public interface Builder {
|
|||||||
/**
|
/**
|
||||||
* Specify the Element Types to scan. If this method is not called,
|
* Specify the Element Types to scan. If this method is not called,
|
||||||
* {@link ElementType#TYPE} is used as default.
|
* {@link ElementType#TYPE} is used as default.
|
||||||
* <p>
|
* <p/>
|
||||||
* Valid types are:
|
* Valid types are:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link ElementType#TYPE}
|
* <li>{@link ElementType#TYPE}
|
||||||
@ -81,18 +82,18 @@ public interface Builder {
|
|||||||
/**
|
/**
|
||||||
* Filter the scanned Class Files based on its name and the directory or jar file it is
|
* Filter the scanned Class Files based on its name and the directory or jar file it is
|
||||||
* stored.
|
* stored.
|
||||||
* <p>
|
* <p/>
|
||||||
* If the Class File is stored as a single file in the file system the {@code File}
|
* If the Class File is stored as a single file in the file system the {@code File}
|
||||||
* argument in {@link FilenameFilter#accept(java.io.File, java.lang.String) } is the
|
* argument in {@link FilenameFilter#accept(java.io.File, java.lang.String) } is the
|
||||||
* absolute path to the root directory scanned.
|
* absolute path to the root directory scanned.
|
||||||
* <p>
|
* <p/>
|
||||||
* If the Class File is stored in a jar file the {@code File} argument in
|
* If the Class File is stored in a jar file the {@code File} argument in
|
||||||
* {@link FilenameFilter#accept(java.io.File, java.lang.String)} is the absolute path of
|
* {@link FilenameFilter#accept(java.io.File, java.lang.String)} is the absolute path of
|
||||||
* the jar file.
|
* the jar file.
|
||||||
* <p>
|
* <p/>
|
||||||
* The {@code String} argument is the full name of the ClassFile in native format,
|
* The {@code String} argument is the full name of the ClassFile in native format,
|
||||||
* including package name, like {@code eu/infomas/annotation/AnnotationDetector$1.class}.
|
* including package name, like {@code eu/infomas/annotation/AnnotationDetector$1.class}.
|
||||||
* <p>
|
* <p/>
|
||||||
* Note that all non-Class Files are already filtered and not seen by the filter.
|
* Note that all non-Class Files are already filtered and not seen by the filter.
|
||||||
*
|
*
|
||||||
* @param filter The filter, never {@code null}
|
* @param filter The filter, never {@code null}
|
||||||
|
@ -21,24 +21,21 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.annotation;
|
package dorkbox.util.annotation;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.*;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code ClassFileBuffer} is used by {@link AnnotationDetector} to efficiently read Java
|
* {@code ClassFileBuffer} is used by {@link AnnotationDetector} to efficiently read Java
|
||||||
* ClassFile files from an {@link InputStream} and parse the content via the {@link DataInput}
|
* ClassFile files from an {@link InputStream} and parse the content via the {@link DataInput}
|
||||||
* interface.
|
* interface.
|
||||||
* <p>
|
* <p/>
|
||||||
* Note that Java ClassFile files can grow really big,
|
* Note that Java ClassFile files can grow really big,
|
||||||
* {@code com.sun.corba.se.impl.logging.ORBUtilSystemException} is 128.2 kb!
|
* {@code com.sun.corba.se.impl.logging.ORBUtilSystemException} is 128.2 kb!
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
final class ClassFileBuffer implements DataInput {
|
final
|
||||||
|
class ClassFileBuffer implements DataInput {
|
||||||
|
|
||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
private int size; // the number of significant bytes read
|
private int size; // the number of significant bytes read
|
||||||
@ -70,7 +67,8 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
* supplied byte stream.
|
* supplied byte stream.
|
||||||
* The read pointer is reset to the start of the byte array.
|
* The read pointer is reset to the start of the byte array.
|
||||||
*/
|
*/
|
||||||
public void readFrom(final InputStream in) throws IOException {
|
public
|
||||||
|
void readFrom(final InputStream in) throws IOException {
|
||||||
this.pointer = 0;
|
this.pointer = 0;
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
int n;
|
int n;
|
||||||
@ -87,7 +85,8 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
* Sets the file-pointer offset, measured from the beginning of this file,
|
* Sets the file-pointer offset, measured from the beginning of this file,
|
||||||
* at which the next read or write occurs.
|
* at which the next read or write occurs.
|
||||||
*/
|
*/
|
||||||
public void seek(final int position) throws IOException {
|
public
|
||||||
|
void seek(final int position) throws IOException {
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
throw new IllegalArgumentException("position < 0: " + position);
|
throw new IllegalArgumentException("position < 0: " + position);
|
||||||
}
|
}
|
||||||
@ -100,20 +99,22 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
/**
|
/**
|
||||||
* Return the size (in bytes) of this Java ClassFile file.
|
* Return the size (in bytes) of this Java ClassFile file.
|
||||||
*/
|
*/
|
||||||
public int size() {
|
public
|
||||||
|
int size() {
|
||||||
return this.size;
|
return this.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataInput
|
// DataInput
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFully(final byte[] bytes) throws IOException {
|
public
|
||||||
|
void readFully(final byte[] bytes) throws IOException {
|
||||||
readFully(bytes, 0, bytes.length);
|
readFully(bytes, 0, bytes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFully(final byte[] bytes, final int offset, final int length)
|
public
|
||||||
throws IOException {
|
void readFully(final byte[] bytes, final int offset, final int length) throws IOException {
|
||||||
|
|
||||||
if (length < 0 || offset < 0 || offset + length > bytes.length) {
|
if (length < 0 || offset < 0 || offset + length > bytes.length) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
@ -126,13 +127,15 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int skipBytes(final int n) throws IOException {
|
public
|
||||||
|
int skipBytes(final int n) throws IOException {
|
||||||
seek(this.pointer + n);
|
seek(this.pointer + n);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte readByte() throws IOException {
|
public
|
||||||
|
byte readByte() throws IOException {
|
||||||
if (this.pointer >= this.size) {
|
if (this.pointer >= this.size) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
@ -140,12 +143,14 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean readBoolean() throws IOException {
|
public
|
||||||
|
boolean readBoolean() throws IOException {
|
||||||
return readByte() != 0;
|
return readByte() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readUnsignedByte() throws IOException {
|
public
|
||||||
|
int readUnsignedByte() throws IOException {
|
||||||
if (this.pointer >= this.size) {
|
if (this.pointer >= this.size) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
@ -153,7 +158,8 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readUnsignedShort() throws IOException {
|
public
|
||||||
|
int readUnsignedShort() throws IOException {
|
||||||
if (this.pointer + 2 > this.size) {
|
if (this.pointer + 2 > this.size) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
@ -161,17 +167,20 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short readShort() throws IOException {
|
public
|
||||||
return (short)readUnsignedShort();
|
short readShort() throws IOException {
|
||||||
|
return (short) readUnsignedShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char readChar() throws IOException {
|
public
|
||||||
return (char)readUnsignedShort();
|
char readChar() throws IOException {
|
||||||
|
return (char) readUnsignedShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readInt() throws IOException {
|
public
|
||||||
|
int readInt() throws IOException {
|
||||||
if (this.pointer + 4 > this.size) {
|
if (this.pointer + 4 > this.size) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
@ -182,14 +191,15 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readLong() throws IOException {
|
public
|
||||||
|
long readLong() throws IOException {
|
||||||
if (this.pointer + 8 > this.size) {
|
if (this.pointer + 8 > this.size) {
|
||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
return ((long)read() << 56) +
|
return ((long) read() << 56) +
|
||||||
((long)read() << 48) +
|
((long) read() << 48) +
|
||||||
((long)read() << 40) +
|
((long) read() << 40) +
|
||||||
((long)read() << 32) +
|
((long) read() << 32) +
|
||||||
(read() << 24) +
|
(read() << 24) +
|
||||||
(read() << 16) +
|
(read() << 16) +
|
||||||
(read() << 8) +
|
(read() << 8) +
|
||||||
@ -197,12 +207,14 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float readFloat() throws IOException {
|
public
|
||||||
|
float readFloat() throws IOException {
|
||||||
return Float.intBitsToFloat(readInt());
|
return Float.intBitsToFloat(readInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double readDouble() throws IOException {
|
public
|
||||||
|
double readDouble() throws IOException {
|
||||||
return Double.longBitsToDouble(readLong());
|
return Double.longBitsToDouble(readLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,22 +226,26 @@ final class ClassFileBuffer implements DataInput {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public String readLine() throws IOException {
|
public
|
||||||
|
String readLine() throws IOException {
|
||||||
throw new UnsupportedOperationException("readLine() is deprecated and not supported");
|
throw new UnsupportedOperationException("readLine() is deprecated and not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readUTF() throws IOException {
|
public
|
||||||
|
String readUTF() throws IOException {
|
||||||
return DataInputStream.readUTF(this);
|
return DataInputStream.readUTF(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
|
|
||||||
private int read() {
|
private
|
||||||
|
int read() {
|
||||||
return this.buffer[this.pointer++] & 0xff;
|
return this.buffer[this.pointer++] & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resizeIfNeeded() {
|
private
|
||||||
|
void resizeIfNeeded() {
|
||||||
if (this.size >= this.buffer.length) {
|
if (this.size >= this.buffer.length) {
|
||||||
final byte[] newBuffer = new byte[this.buffer.length * 2];
|
final byte[] newBuffer = new byte[this.buffer.length * 2];
|
||||||
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
|
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
|
||||||
|
@ -21,22 +21,19 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.annotation;
|
package dorkbox.util.annotation;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
|
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
|
||||||
* a specific context.
|
* a specific context.
|
||||||
* <p>
|
* <p/>
|
||||||
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
|
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
public class ClassFileIterator implements ClassIterator {
|
public
|
||||||
|
class ClassFileIterator implements ClassIterator {
|
||||||
|
|
||||||
private FileIterator fileIter;
|
private FileIterator fileIter;
|
||||||
protected final String[] pkgNameFilter;
|
protected final String[] pkgNameFilter;
|
||||||
@ -47,24 +44,26 @@ public class ClassFileIterator implements ClassIterator {
|
|||||||
/**
|
/**
|
||||||
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
|
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
|
||||||
* from the specified files and/or directories, including sub directories.
|
* from the specified files and/or directories, including sub directories.
|
||||||
* <p>
|
* <p/>
|
||||||
* If the (optional) package filter is defined, only class files staring with one of the
|
* If the (optional) package filter is defined, only class files staring with one of the
|
||||||
* defined package names are returned.
|
* defined package names are returned.
|
||||||
* NOTE: package names must be defined in the native format (using '/' instead of '.').
|
* NOTE: package names must be defined in the native format (using '/' instead of '.').
|
||||||
*/
|
*/
|
||||||
protected ClassFileIterator(final String[] pkgNameFilter) {
|
protected
|
||||||
|
ClassFileIterator(final String[] pkgNameFilter) {
|
||||||
this.pkgNameFilter = pkgNameFilter;
|
this.pkgNameFilter = pkgNameFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
|
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
|
||||||
* from the specified files and/or directories, including sub directories.
|
* from the specified files and/or directories, including sub directories.
|
||||||
* <p>
|
* <p/>
|
||||||
* If the (optional) package filter is defined, only class files staring with one of the
|
* If the (optional) package filter is defined, only class files staring with one of the
|
||||||
* defined package names are returned.
|
* defined package names are returned.
|
||||||
* NOTE: package names must be defined in the native format (using '/' instead of '.').
|
* NOTE: package names must be defined in the native format (using '/' instead of '.').
|
||||||
*/
|
*/
|
||||||
protected ClassFileIterator(final File[] filesOrDirectories, final String[] pkgNameFilter) {
|
protected
|
||||||
|
ClassFileIterator(final File[] filesOrDirectories, final String[] pkgNameFilter) {
|
||||||
this.fileIter = new FileIterator(filesOrDirectories);
|
this.fileIter = new FileIterator(filesOrDirectories);
|
||||||
this.pkgNameFilter = pkgNameFilter;
|
this.pkgNameFilter = pkgNameFilter;
|
||||||
}
|
}
|
||||||
@ -74,11 +73,10 @@ public class ClassFileIterator implements ClassIterator {
|
|||||||
* The name is either the path name of a file or the name of an ZIP/JAR file entry.
|
* The name is either the path name of a file or the name of an ZIP/JAR file entry.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public
|
||||||
|
String getName() {
|
||||||
// Both getPath() and getName() are very light weight method calls
|
// Both getPath() and getName() are very light weight method calls
|
||||||
return this.zipIter == null ?
|
return this.zipIter == null ? this.fileIter.getFile().getPath() : this.zipIter.getEntry().getName();
|
||||||
this.fileIter.getFile().getPath() :
|
|
||||||
this.zipIter.getEntry().getName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,37 +86,43 @@ public class ClassFileIterator implements ClassIterator {
|
|||||||
* ZIP File Entry.
|
* ZIP File Entry.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isFile() {
|
public
|
||||||
|
boolean isFile() {
|
||||||
return this.isFile;
|
return this.isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next Java ClassFile as an {@code InputStream}.
|
* Return the next Java ClassFile as an {@code InputStream}.
|
||||||
* <p>
|
* <p/>
|
||||||
* NOTICE: Client code MUST close the returned {@code InputStream}!
|
* NOTICE: Client code MUST close the returned {@code InputStream}!
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InputStream next(final FilenameFilter filter) throws IOException {
|
public
|
||||||
|
InputStream next(final FilenameFilter filter) throws IOException {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.zipIter == null) {
|
if (this.zipIter == null) {
|
||||||
final File file = this.fileIter.next();
|
final File file = this.fileIter.next();
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
final String path = file.getPath();
|
final String path = file.getPath();
|
||||||
if (path.endsWith(".class") && (filter == null ||
|
if (path.endsWith(".class") && (filter == null || filter.accept(this.fileIter.getRootFile(), this.fileIter.relativize(
|
||||||
filter.accept(this.fileIter.getRootFile(), this.fileIter.relativize(path)))) {
|
path)))) {
|
||||||
this.isFile = true;
|
this.isFile = true;
|
||||||
return new FileInputStream(file);
|
return new FileInputStream(file);
|
||||||
} else if (this.fileIter.isRootFile() && endsWithIgnoreCase(path, ".jar")) {
|
}
|
||||||
|
else if (this.fileIter.isRootFile() && endsWithIgnoreCase(path, ".jar")) {
|
||||||
this.zipIter = new ZipFileIterator(file, this.pkgNameFilter);
|
this.zipIter = new ZipFileIterator(file, this.pkgNameFilter);
|
||||||
} // else just ignore
|
} // else just ignore
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
final InputStream is = this.zipIter.next(filter);
|
final InputStream is = this.zipIter.next(filter);
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
this.zipIter = null;
|
this.zipIter = null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.isFile = false;
|
this.isFile = false;
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
@ -128,7 +132,8 @@ public class ClassFileIterator implements ClassIterator {
|
|||||||
|
|
||||||
// private
|
// private
|
||||||
|
|
||||||
private static boolean endsWithIgnoreCase(final String value, final String suffix) {
|
private static
|
||||||
|
boolean endsWithIgnoreCase(final String value, final String suffix) {
|
||||||
final int n = suffix.length();
|
final int n = suffix.length();
|
||||||
return value.regionMatches(true, value.length() - n, suffix, 0, n);
|
return value.regionMatches(true, value.length() - n, suffix, 0, n);
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,14 @@ import java.io.InputStream;
|
|||||||
/**
|
/**
|
||||||
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
|
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
|
||||||
* a specific context.
|
* a specific context.
|
||||||
* <p>
|
* <p/>
|
||||||
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
|
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
public interface ClassIterator {
|
public
|
||||||
|
interface ClassIterator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the name of the Java ClassFile returned from the last call to {@link #next()}.
|
* Return the name of the Java ClassFile returned from the last call to {@link #next()}.
|
||||||
@ -55,7 +56,7 @@ public interface ClassIterator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next Java ClassFile as an {@code InputStream}.
|
* Return the next Java ClassFile as an {@code InputStream}.
|
||||||
* <p>
|
* <p/>
|
||||||
* NOTICE: Client code MUST close the returned {@code InputStream}!
|
* NOTICE: Client code MUST close the returned {@code InputStream}!
|
||||||
*/
|
*/
|
||||||
InputStream next(final FilenameFilter filter) throws IOException;
|
InputStream next(final FilenameFilter filter) throws IOException;
|
||||||
|
@ -33,7 +33,8 @@ import java.lang.reflect.Method;
|
|||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.1.0
|
* @since annotation-detector 3.1.0
|
||||||
*/
|
*/
|
||||||
public interface Cursor {
|
public
|
||||||
|
interface Cursor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the type name of the currently reported Java Class File.
|
* Return the type name of the currently reported Java Class File.
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.annotation;
|
package dorkbox.util.annotation;
|
||||||
|
|
||||||
|
import dorkbox.util.FileUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -26,17 +28,17 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import dorkbox.util.FileUtil;
|
public
|
||||||
|
class CustomClassloaderIterator implements ClassIterator {
|
||||||
|
|
||||||
public class CustomClassloaderIterator implements ClassIterator {
|
private final Iterator<URL> loaderFilesIterator;
|
||||||
|
|
||||||
private volatile Iterator<URL> loaderFilesIterator;
|
|
||||||
private ClassFileIterator classFileIterator;
|
private ClassFileIterator classFileIterator;
|
||||||
|
|
||||||
// have to support
|
// have to support
|
||||||
// 1 - scanning the classpath
|
// 1 - scanning the classpath
|
||||||
// 2 - scanning a specific package
|
// 2 - scanning a specific package
|
||||||
public CustomClassloaderIterator(List<URL> fileNames, String[] packageNames) throws IOException {
|
public
|
||||||
|
CustomClassloaderIterator(List<URL> fileNames, String[] packageNames) throws IOException {
|
||||||
// if ANY of our filenames DO NOT start with "box", we have to add it as a file, so our iterator picks it up (and if dir, it's childred)
|
// if ANY of our filenames DO NOT start with "box", we have to add it as a file, so our iterator picks it up (and if dir, it's childred)
|
||||||
|
|
||||||
Set<File> files = new HashSet<File>();
|
Set<File> files = new HashSet<File>();
|
||||||
@ -56,7 +58,8 @@ public class CustomClassloaderIterator implements ClassIterator {
|
|||||||
|
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
this.classFileIterator = null;
|
this.classFileIterator = null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.classFileIterator = new ClassFileIterator(files.toArray(new File[0]), packageNames);
|
this.classFileIterator = new ClassFileIterator(files.toArray(new File[0]), packageNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,13 +68,15 @@ public class CustomClassloaderIterator implements ClassIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public
|
||||||
|
String getName() {
|
||||||
// not needed
|
// not needed
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFile() {
|
public
|
||||||
|
boolean isFile() {
|
||||||
if (this.classFileIterator != null) {
|
if (this.classFileIterator != null) {
|
||||||
return this.classFileIterator.isFile();
|
return this.classFileIterator.isFile();
|
||||||
}
|
}
|
||||||
@ -80,13 +85,15 @@ public class CustomClassloaderIterator implements ClassIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream next(FilenameFilter filter) throws IOException {
|
public
|
||||||
|
InputStream next(FilenameFilter filter) throws IOException {
|
||||||
if (this.classFileIterator != null) {
|
if (this.classFileIterator != null) {
|
||||||
while (true) {
|
while (true) {
|
||||||
InputStream next = this.classFileIterator.next(filter);
|
InputStream next = this.classFileIterator.next(filter);
|
||||||
if (next == null) {
|
if (next == null) {
|
||||||
this.classFileIterator = null;
|
this.classFileIterator = null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
String name = this.classFileIterator.getName();
|
String name = this.classFileIterator.getName();
|
||||||
if (name.endsWith(".class")) {
|
if (name.endsWith(".class")) {
|
||||||
return next;
|
return next;
|
||||||
|
@ -29,7 +29,7 @@ import java.util.NoSuchElementException;
|
|||||||
/**
|
/**
|
||||||
* {@code FileIterator} enables iteration over all files in a directory and all its sub
|
* {@code FileIterator} enables iteration over all files in a directory and all its sub
|
||||||
* directories.
|
* directories.
|
||||||
* <p>
|
* <p/>
|
||||||
* Usage:
|
* Usage:
|
||||||
* <pre>
|
* <pre>
|
||||||
* FileIterator iter = new FileIterator(new File("./src"));
|
* FileIterator iter = new FileIterator(new File("./src"));
|
||||||
@ -43,7 +43,8 @@ import java.util.NoSuchElementException;
|
|||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
final class FileIterator {
|
final
|
||||||
|
class FileIterator {
|
||||||
|
|
||||||
private final Deque<File> stack = new LinkedList<File>();
|
private final Deque<File> stack = new LinkedList<File>();
|
||||||
private int rootCount;
|
private int rootCount;
|
||||||
@ -52,7 +53,7 @@ final class FileIterator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@code FileIterator} using the specified 'filesOrDirectories' as root.
|
* Create a new {@code FileIterator} using the specified 'filesOrDirectories' as root.
|
||||||
* <p>
|
* <p/>
|
||||||
* If 'filesOrDirectories' contains a file, the iterator just returns that single file.
|
* If 'filesOrDirectories' contains a file, the iterator just returns that single file.
|
||||||
* If 'filesOrDirectories' contains a directory, all files in that directory
|
* If 'filesOrDirectories' contains a directory, all files in that directory
|
||||||
* and its sub directories are returned (depth first).
|
* and its sub directories are returned (depth first).
|
||||||
@ -80,12 +81,12 @@ final class FileIterator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Relativize the absolute full (file) 'path' against the current root file.
|
* Relativize the absolute full (file) 'path' against the current root file.
|
||||||
* <p>
|
* <p/>
|
||||||
* Example:<br/>
|
* Example:<br/>
|
||||||
* Let current root be "/path/to/dir".
|
* Let current root be "/path/to/dir".
|
||||||
* Then {@code relativize("/path/to/dir/with/file.ext")} equals "with/file.ext" (without
|
* Then {@code relativize("/path/to/dir/with/file.ext")} equals "with/file.ext" (without
|
||||||
* leading '/').
|
* leading '/').
|
||||||
* <p>
|
* <p/>
|
||||||
* Note: the paths are not canonicalized!
|
* Note: the paths are not canonicalized!
|
||||||
*/
|
*/
|
||||||
String relativize(final String path) {
|
String relativize(final String path) {
|
||||||
@ -115,7 +116,8 @@ final class FileIterator {
|
|||||||
if (this.stack.isEmpty()) {
|
if (this.stack.isEmpty()) {
|
||||||
this.current = null;
|
this.current = null;
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.current = this.stack.removeLast();
|
this.current = this.stack.removeLast();
|
||||||
if (this.current.isDirectory()) {
|
if (this.current.isDirectory()) {
|
||||||
if (this.stack.size() < this.rootCount) {
|
if (this.stack.size() < this.rootCount) {
|
||||||
@ -124,7 +126,8 @@ final class FileIterator {
|
|||||||
}
|
}
|
||||||
addReverse(this.current.listFiles());
|
addReverse(this.current.listFiles());
|
||||||
return next();
|
return next();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return this.current;
|
return this.current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +138,8 @@ final class FileIterator {
|
|||||||
/**
|
/**
|
||||||
* Add the specified files in reverse order.
|
* Add the specified files in reverse order.
|
||||||
*/
|
*/
|
||||||
private void addReverse(final File[] files) {
|
private
|
||||||
|
void addReverse(final File[] files) {
|
||||||
for (int i = files.length - 1; i >= 0; --i) {
|
for (int i = files.length - 1; i >= 0; --i) {
|
||||||
this.stack.add(files[i]);
|
this.stack.add(files[i]);
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,21 @@ package dorkbox.util.annotation;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code Reporter} is used to report the detected annotations.
|
* {@code Reporter} is used to report the detected annotations.
|
||||||
* <p>
|
* <p/>
|
||||||
* This interface is a so called "Single Abstract Method" (SAM) or "Functional Interface", so
|
* This interface is a so called "Single Abstract Method" (SAM) or "Functional Interface", so
|
||||||
* can be used as a Lambda in Java 8 (see examples).
|
* can be used as a Lambda in Java 8 (see examples).
|
||||||
*
|
*
|
||||||
* @see Builder#report(dorkbox.util.annotation.Reporter)
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
|
* @see Builder#report(dorkbox.util.annotation.Reporter)
|
||||||
* @since annotation-detector 3.1.0
|
* @since annotation-detector 3.1.0
|
||||||
*/
|
*/
|
||||||
public interface Reporter {
|
public
|
||||||
|
interface Reporter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when an {@code Annotation} is detected. Invoke methods on the
|
* This method is called when an {@code Annotation} is detected. Invoke methods on the
|
||||||
* provided {@code Cursor} reference to get more specific information about the
|
* provided {@code Cursor} reference to get more specific information about the
|
||||||
* {@code Annotation}.
|
* {@code Annotation}.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
void report(Cursor cursor);
|
void report(Cursor cursor);
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ package dorkbox.util.annotation;
|
|||||||
/**
|
/**
|
||||||
* {@code ReporterFunction} is used to report the detected annotations.
|
* {@code ReporterFunction} is used to report the detected annotations.
|
||||||
*
|
*
|
||||||
* @see Builder#collect(dorkbox.util.annotation.ReporterFunction)
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
|
* @see Builder#collect(dorkbox.util.annotation.ReporterFunction)
|
||||||
* @since annotation-detector 3.1.0
|
* @since annotation-detector 3.1.0
|
||||||
*/
|
*/
|
||||||
public interface ReporterFunction<T> {
|
public
|
||||||
|
interface ReporterFunction<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when an {@code Annotation} is detected.
|
* This method is called when an {@code Annotation} is detected.
|
||||||
|
@ -32,15 +32,16 @@ import java.util.zip.ZipFile;
|
|||||||
/**
|
/**
|
||||||
* {@code ZipFileIterator} is used to iterate over all entries in a given {@code zip} or
|
* {@code ZipFileIterator} is used to iterate over all entries in a given {@code zip} or
|
||||||
* {@code jar} file and returning the {@link InputStream} of these entries.
|
* {@code jar} file and returning the {@link InputStream} of these entries.
|
||||||
* <p>
|
* <p/>
|
||||||
* It is possible to specify an (optional) entry name filter.
|
* It is possible to specify an (optional) entry name filter.
|
||||||
* <p>
|
* <p/>
|
||||||
* The most efficient way of iterating is used, see benchmark in test classes.
|
* The most efficient way of iterating is used, see benchmark in test classes.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
|
||||||
* @since annotation-detector 3.0.0
|
* @since annotation-detector 3.0.0
|
||||||
*/
|
*/
|
||||||
final class ZipFileIterator {
|
final
|
||||||
|
class ZipFileIterator {
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final ZipFile zipFile;
|
private final ZipFile zipFile;
|
||||||
@ -64,11 +65,13 @@ final class ZipFileIterator {
|
|||||||
this.entries = this.zipFile.entries();
|
this.entries = this.zipFile.entries();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZipEntry getEntry() {
|
public
|
||||||
|
ZipEntry getEntry() {
|
||||||
return this.current;
|
return this.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream next(final FilenameFilter filter) throws IOException {
|
public
|
||||||
|
InputStream next(final FilenameFilter filter) throws IOException {
|
||||||
while (this.entries.hasMoreElements()) {
|
while (this.entries.hasMoreElements()) {
|
||||||
this.current = this.entries.nextElement();
|
this.current = this.entries.nextElement();
|
||||||
if (filter == null || accept(this.current, filter)) {
|
if (filter == null || accept(this.current, filter)) {
|
||||||
@ -85,7 +88,8 @@ final class ZipFileIterator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean accept(final ZipEntry entry, final FilenameFilter filter) {
|
private
|
||||||
|
boolean accept(final ZipEntry entry, final FilenameFilter filter) {
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user