Added intellij support. Compiled as java6

This commit is contained in:
nathan 2015-06-28 00:07:01 +02:00
parent 6ffa6711bb
commit d3a931ab36
13 changed files with 319 additions and 244 deletions

View File

@ -7,13 +7,13 @@
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
</src_description>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<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="library" name="logging slf4j-api (1.7.5)" level="application" />
<orderEntry type="library" name="bouncyCastle bcpkix-jdk15on (1.51)" level="application" />

View File

@ -24,52 +24,61 @@ import java.lang.reflect.Method;
/**
* 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>() {
@Override
public String report(Cursor cursor) {
public
String report(Cursor cursor) {
return cursor.getTypeName();
}
};
public static final ReporterFunction<Class<? extends Annotation>> getAnnotationType = new ReporterFunction<Class<? extends Annotation>>() {
@Override
public Class<? extends Annotation> report(Cursor cursor) {
public
Class<? extends Annotation> report(Cursor cursor) {
return cursor.getAnnotationType();
}
};
public static final ReporterFunction<ElementType> getElementType = new ReporterFunction<ElementType>() {
@Override
public ElementType report(Cursor cursor) {
public
ElementType report(Cursor cursor) {
return cursor.getElementType();
}
};
public static final ReporterFunction<String> getMemberName = new ReporterFunction<String>() {
@Override
public String report(Cursor cursor) {
public
String report(Cursor cursor) {
return cursor.getMemberName();
}
};
public static final ReporterFunction<Class<?>> getType = new ReporterFunction<Class<?>>() {
@Override
public Class<?> report(Cursor cursor) {
public
Class<?> report(Cursor cursor) {
return cursor.getType();
}
};
public static final ReporterFunction<Constructor<?>> getConstructor = new ReporterFunction<Constructor<?>>() {
@Override
public Constructor<?> report(Cursor cursor) {
public
Constructor<?> report(Cursor cursor) {
return cursor.getConstructor();
}
};
public static final ReporterFunction<Field> getField = new ReporterFunction<Field>() {
@Override
public Field report(Cursor cursor) {
public
Field report(Cursor cursor) {
return cursor.getField();
}
};
public static final ReporterFunction<Method> getMethod = new ReporterFunction<Method>() {
@Override
public Method report(Cursor cursor) {
public
Method report(Cursor cursor) {
return cursor.getMethod();
}
};

View File

@ -21,11 +21,9 @@
*/
package dorkbox.util.annotation;
import java.io.DataInput;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.AnnotatedElement;
@ -35,29 +33,18 @@ import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
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;
import java.util.*;
/**
* {@code AnnotationDetector} reads Java Class Files ("*.class") and reports the
* 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
* 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,
* 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}.
* <p>
* <p/>
* A class file consists of a single ClassFile structure:
* <pre>
* ClassFile {
@ -97,7 +84,7 @@ import org.slf4j.LoggerFactory;
* <li><a href="http://stackoverflow.com/questions/259140">scanning java annotations at
* runtime</a>.
* </ul>
* <p>
* <p/>
* Similar projects / libraries:
* <ul>
* <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};
* <li>If using the Spring Framework, use {@code ClassPathScanningCandidateComponentProvider}
* </ul>
* <p>
* <p/>
* All above mentioned projects make use of a byte code manipulation library (like BCEL,
* ASM or Javassist).
*
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @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);
// Constant Pool type tags
// Constant Pool type ta gs
private static final int CP_UTF8 = 1;
private static final int CP_INTEGER = 3;
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
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;
if (iterator == null) {
this.cfIterator = new ClassFileIterator(filesOrDirectories, pkgNameFilter);
if (filesOrDirectories.length == 0) {
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;
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
* on the class path are scanned.
*/
public static Builder scanClassPath(final String... packageNames)
throws IOException {
public static
Builder scanClassPath(final String... packageNames) throws IOException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
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
* on the class path are scanned.
*/
public static Builder scanClassPath(ClassLoader loader, final String... packageNames)
throws IOException {
public static
Builder scanClassPath(ClassLoader loader, final String... packageNames) throws IOException {
final String[] pkgNameFilter;
@ -259,7 +249,8 @@ public final class AnnotationDetector implements Builder, Cursor {
}
return new AnnotationDetector(loader, null, new CustomClassloaderIterator(fileNames, packageNames), pkgNameFilter);
} else {
}
else {
final Set<File> files = new HashSet<File>();
if (packageNames.length == 0) {
@ -268,7 +259,8 @@ public final class AnnotationDetector implements Builder, Cursor {
for (int i = 0; i < fileNames.length; ++i) {
files.add(new File(fileNames[i]));
}
} else {
}
else {
pkgNameFilter = new String[packageNames.length];
for (int i = 0; i < pkgNameFilter.length; ++i) {
pkgNameFilter[i] = packageNames[i].replace('.', '/');
@ -288,7 +280,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* Factory method, starting point for the fluent interface.
* 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);
}
@ -296,7 +289,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* Factory method, starting point for the fluent interface.
* 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);
}
@ -304,7 +298,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* Factory method, starting point for the fluent interface.
* 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);
}
@ -312,7 +307,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Builder#forAnnotations(java.lang.Class...) }.
*/
@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);
// map "raw" type names to Class object
this.annotations.put("L" + annotation.getName().replace('.', '/') + ";", annotation);
@ -324,7 +320,8 @@ public final class AnnotationDetector implements Builder, Cursor {
*/
@SuppressWarnings("unchecked")
@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);
// map "raw" type names to Class object
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...) }.
*/
@Override
public Builder on(final ElementType type) {
public
Builder on(final ElementType type) {
if (type == null) {
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...) }.
*/
@Override
public Builder on(final ElementType... types) {
public
Builder on(final ElementType... types) {
if (types.length == 0) {
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) }.
*/
@Override
public Builder filter(final FilenameFilter filter) {
public
Builder filter(final FilenameFilter filter) {
if (filter == 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) }.
*/
@Override
public void report(final Reporter reporter) throws IOException {
public
void report(final Reporter reporter) throws IOException {
this.reporter = reporter;
detect(this.cfIterator);
}
@ -404,12 +405,14 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Builder#collect(dorkbox.util.annotation.AnnotationDetector.ReporterFunction) }.
*/
@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>();
this.reporter = new Reporter() {
@Override
public void report(Cursor cursor) {
public
void report(Cursor cursor) {
list.add(reporter.report(cursor));
}
@ -422,7 +425,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getTypeName() }.
*/
@Override
public String getTypeName() {
public
String getTypeName() {
return this.typeName.replace('/', '.');
}
@ -430,7 +434,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getAnnotationType() }.
*/
@Override
public Class<? extends Annotation> getAnnotationType() {
public
Class<? extends Annotation> getAnnotationType() {
return this.annotationType;
}
@ -438,7 +443,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getElementType() }.
*/
@Override
public ElementType getElementType() {
public
ElementType getElementType() {
return this.elementType;
}
@ -446,7 +452,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getMemberName() }.
*/
@Override
public String getMemberName() {
public
String getMemberName() {
return this.memberName;
}
@ -454,7 +461,8 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getType() }.
*/
@Override
public Class<?> getType() {
public
Class<?> getType() {
return loadClass(this.loader, getTypeName());
}
@ -462,16 +470,15 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getField() }.
*/
@Override
public Field getField() {
public
Field getField() {
if (this.elementType != ElementType.FIELD) {
throw new IllegalStateException(
"Illegal to call getField() when " + this.elementType + " is reported");
throw new IllegalStateException("Illegal to call getField() when " + this.elementType + " is reported");
}
try {
return getType().getDeclaredField(this.memberName);
} catch (NoSuchFieldException ex) {
throw assertionError(
"Cannot find Field '%s' for type %s", this.memberName, getTypeName());
throw assertionError("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() }.
*/
@Override
public Constructor<?> getConstructor() {
public
Constructor<?> getConstructor() {
if (this.elementType != ElementType.CONSTRUCTOR) {
throw new IllegalStateException(
"Illegal to call getMethod() when " + this.elementType + " is reported");
throw new IllegalStateException("Illegal to call getMethod() when " + this.elementType + " is reported");
}
try {
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
return getType().getConstructor(parameterTypes);
} catch (NoSuchMethodException ex) {
throw assertionError(
"Cannot find Contructor '%s(...)' for type %s", this.memberName, getTypeName());
throw assertionError("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() }.
*/
@Override
public Method getMethod() {
public
Method getMethod() {
if (this.elementType != ElementType.METHOD) {
throw new IllegalStateException(
"Illegal to call getMethod() when " + this.elementType + " is reported");
throw new IllegalStateException("Illegal to call getMethod() when " + this.elementType + " is reported");
}
try {
final Class<?>[] parameterTypes = parseArguments(this.methodDescriptor);
return getType().getDeclaredMethod(this.memberName, parameterTypes);
} catch (NoSuchMethodException ex) {
throw assertionError(
"Cannot find Method '%s(...)' for type %s", this.memberName, getTypeName());
throw assertionError("Cannot find Method '%s(...)' for type %s", this.memberName, getTypeName());
}
}
@ -515,10 +520,11 @@ public final class AnnotationDetector implements Builder, Cursor {
* See {@link Cursor#getAnnotation(java.lang.Class) }.
*/
@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)) {
throw new IllegalStateException("Illegal to call getAnnotation() when " +
this.annotationType.getName() + " is reported");
this.annotationType.getName() + " is reported");
}
final AnnotatedElement ae;
switch (this.elementType) {
@ -539,8 +545,8 @@ public final class AnnotationDetector implements Builder, Cursor {
// private
private static void addFiles(ClassLoader loader, String resourceName, Set<File> files)
throws IOException {
private static
void addFiles(ClassLoader loader, String resourceName, Set<File> files) throws IOException {
final Enumeration<URL> resourceEnum = loader.getResources(resourceName);
while (resourceEnum.hasMoreElements()) {
@ -557,7 +563,8 @@ public final class AnnotationDetector implements Builder, Cursor {
final File dir = toFile(url);
if (dir.isDirectory()) {
files.add(dir);
} else if (isVfs) {
}
else if (isVfs) {
//Jar file via JBoss VFS protocol - strip package name
String jarPath = dir.getPath();
final int idx = jarPath.indexOf(".jar");
@ -568,23 +575,26 @@ public final class AnnotationDetector implements Builder, Cursor {
files.add(jarFile);
}
}
} else {
}
else {
throw assertionError("Not a recognized file URL: %s", url);
}
} else {
}
else {
// Resource in Jar File
final File jarFile =
toFile(((JarURLConnection)url.openConnection()).getJarFileURL());
final File jarFile = toFile(((JarURLConnection) url.openConnection()).getJarFileURL());
if (jarFile.isFile()) {
files.add(jarFile);
} else {
}
else {
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
// Do not use URLDecoder
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;
boolean mustEndInClass = iterator instanceof ClassFileIterator;
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 {
return buffer.size() > 4 && buffer.readInt() == 0xCAFEBABE;
private
boolean hasCafebabe(final ClassFileBuffer buffer) throws IOException {
return buffer.size() > 4 && buffer.readInt() == 0xCAFEBABE;
}
/**
* 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);
readConstantPoolEntries(di);
readAccessFlags(di);
@ -639,18 +652,21 @@ public final class AnnotationDetector implements Builder, Cursor {
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)
if (LOG.isTraceEnabled()) {
int minor = di.readUnsignedShort();
int maj = di.readUnsignedShort();
LOG.trace("Java Class version {}.{}", maj, minor);
} else {
}
else {
di.skipBytes(4);
}
}
private void readConstantPoolEntries(final DataInput di) throws IOException {
private
void readConstantPoolEntries(final DataInput di) throws IOException {
final int count = di.readUnsignedShort();
this.constantPool = new Object[count];
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).
*/
private boolean readConstantPoolEntry(final DataInput di, final int index)
throws IOException {
private
boolean readConstantPoolEntry(final DataInput di, final int index) throws IOException {
final int tag = di.readUnsignedByte();
switch (tag) {
@ -697,29 +713,33 @@ public final class AnnotationDetector implements Builder, Cursor {
this.constantPool[index] = di.readUnsignedShort();
return false;
default:
throw new ClassFormatError(
"Unkown tag value for constant pool entry: " + tag);
throw new ClassFormatError("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
}
private void readThisClass(final DataInput di) throws IOException {
private
void readThisClass(final DataInput di) throws IOException {
this.typeName = resolveUtf8(di);
}
private void readSuperClass(final DataInput di) throws IOException {
private
void readSuperClass(final DataInput di) throws IOException {
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();
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();
for (int i = 0; i < count; ++i) {
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();
for (int i = 0; i < count; ++i) {
readAccessFlags(di);
@ -743,28 +764,28 @@ public final class AnnotationDetector implements Builder, Cursor {
}
}
private void readAttributes(final DataInput di, final ElementType reporterType)
throws IOException {
private
void readAttributes(final DataInput di, final ElementType reporterType) throws IOException {
final int count = di.readUnsignedShort();
for (int i = 0; i < count; ++i) {
final String name = resolveUtf8(di);
// in bytes, use this to skip the attribute info block
final int length = di.readInt();
if (this.elementTypes.contains(reporterType) &&
("RuntimeVisibleAnnotations".equals(name) ||
"RuntimeInvisibleAnnotations".equals(name))) {
if (this.elementTypes.contains(reporterType) && ("RuntimeVisibleAnnotations".equals(name) ||
"RuntimeInvisibleAnnotations".equals(name))) {
LOG.trace("Attribute: {}", name);
readAnnotations(di, reporterType);
} else {
}
else {
LOG.trace("Attribute: {} (ignored)", name);
di.skipBytes(length);
}
}
}
private void readAnnotations(final DataInput di, final ElementType elementType)
throws IOException {
private
void readAnnotations(final DataInput di, final ElementType elementType) throws IOException {
// the number of Runtime(In)VisibleAnnotations
final int count = di.readUnsignedShort();
@ -775,21 +796,23 @@ public final class AnnotationDetector implements Builder, Cursor {
LOG.trace("Annotation: {} (ignored)", rawTypeName);
continue;
}
LOG.trace("Annotation: ''{}'' on type ''{}'', member ''{}'' (reported)",
this.annotationType.getName(), getTypeName(), getMemberName());
LOG.trace("Annotation: ''{}'' on type ''{}'', member ''{}'' (reported)", this.annotationType.getName(), getTypeName(),
getMemberName());
this.elementType = elementType;
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);
// num_element_value_pairs
final int count = di.readUnsignedShort();
for (int i = 0; i < count; ++i) {
if (LOG.isTraceEnabled()) {
LOG.trace("Anntotation Element: {}", resolveUtf8(di));
} else {
}
else {
di.skipBytes(2);
}
readAnnotationElementValue(di);
@ -797,7 +820,8 @@ public final class AnnotationDetector implements Builder, Cursor {
return rawTypeName;
}
private void readAnnotationElementValue(final DataInput di) throws IOException {
private
void readAnnotationElementValue(final DataInput di) throws IOException {
final int tag = di.readUnsignedByte();
switch (tag) {
case BYTE:
@ -827,8 +851,7 @@ public final class AnnotationDetector implements Builder, Cursor {
}
break;
default:
throw new ClassFormatError("Not a valid annotation element type tag: 0x" +
Integer.toHexString(tag));
throw new ClassFormatError("Not a valid annotation element type tag: 0x" + 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
* (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 Object value = this.constantPool[index];
final String s;
if (value instanceof Integer) {
s = (String)this.constantPool[(Integer)value];
} else {
s = (String)value;
s = (String) this.constantPool[(Integer) value];
}
else {
s = (String) value;
}
return s;
}
@ -854,7 +879,8 @@ public final class AnnotationDetector implements Builder, Cursor {
*/
// incorrect detection of dereferencing possible null pointer
// 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();
// "minimal" descriptor: no arguments: "()V", first character is always '('
if (n < 3 || descriptor.charAt(0) != '(') {
@ -866,7 +892,8 @@ public final class AnnotationDetector implements Builder, Cursor {
if (i == 1) {
if (c == ')') {
return new Class<?>[0];
} else {
}
else {
args = new LinkedList<Class<?>>();
}
}
@ -929,25 +956,26 @@ public final class AnnotationDetector implements Builder, Cursor {
/**
* 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('/', '.');
try {
return Class.forName(typeName, false, loader);
} catch (ClassNotFoundException ex) {
throw assertionError(
"Cannot load type '%s', scanned file not on class path? (%s)", typeName, ex);
throw assertionError("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.
*/
private static AssertionError unparseable(final String descriptor, final String cause) {
return assertionError(
"Unparseble method descriptor: '%s' (cause: %s)", descriptor, cause);
private static
AssertionError unparseable(final String descriptor, final String 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));
}

View File

@ -34,7 +34,8 @@ import java.util.List;
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @since annotation-detector 3.1.0
*/
public interface Builder {
public
interface Builder {
/**
* 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,
* {@link ElementType#TYPE} is used as default.
* <p>
* <p/>
* Valid types are:
* <ul>
* <li>{@link ElementType#TYPE}
@ -66,7 +67,7 @@ public interface Builder {
/**
* Specify the Element Types to scan. If this method is not called,
* {@link ElementType#TYPE} is used as default.
* <p>
* <p/>
* Valid types are:
* <ul>
* <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
* stored.
* <p>
* <p/>
* 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
* absolute path to the root directory scanned.
* <p>
* <p/>
* 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
* the jar file.
* <p>
* <p/>
* 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}.
* <p>
* <p/>
* Note that all non-Class Files are already filtered and not seen by the filter.
*
* @param filter The filter, never {@code null}

View File

@ -21,24 +21,21 @@
*/
package dorkbox.util.annotation;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
/**
* {@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}
* interface.
* <p>
* <p/>
* Note that Java ClassFile files can grow really big,
* {@code com.sun.corba.se.impl.logging.ORBUtilSystemException} is 128.2 kb!
*
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @since annotation-detector 3.0.0
*/
final class ClassFileBuffer implements DataInput {
final
class ClassFileBuffer implements DataInput {
private byte[] buffer;
private int size; // the number of significant bytes read
@ -70,7 +67,8 @@ final class ClassFileBuffer implements DataInput {
* supplied byte stream.
* 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.size = 0;
int n;
@ -87,7 +85,8 @@ final class ClassFileBuffer implements DataInput {
* Sets the file-pointer offset, measured from the beginning of this file,
* 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) {
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.
*/
public int size() {
public
int size() {
return this.size;
}
// DataInput
@Override
public void readFully(final byte[] bytes) throws IOException {
public
void readFully(final byte[] bytes) throws IOException {
readFully(bytes, 0, bytes.length);
}
@Override
public void readFully(final byte[] bytes, final int offset, final int length)
throws IOException {
public
void readFully(final byte[] bytes, final int offset, final int length) throws IOException {
if (length < 0 || offset < 0 || offset + length > bytes.length) {
throw new IndexOutOfBoundsException();
@ -126,13 +127,15 @@ final class ClassFileBuffer implements DataInput {
}
@Override
public int skipBytes(final int n) throws IOException {
public
int skipBytes(final int n) throws IOException {
seek(this.pointer + n);
return n;
}
@Override
public byte readByte() throws IOException {
public
byte readByte() throws IOException {
if (this.pointer >= this.size) {
throw new EOFException();
}
@ -140,12 +143,14 @@ final class ClassFileBuffer implements DataInput {
}
@Override
public boolean readBoolean() throws IOException {
public
boolean readBoolean() throws IOException {
return readByte() != 0;
}
@Override
public int readUnsignedByte() throws IOException {
public
int readUnsignedByte() throws IOException {
if (this.pointer >= this.size) {
throw new EOFException();
}
@ -153,7 +158,8 @@ final class ClassFileBuffer implements DataInput {
}
@Override
public int readUnsignedShort() throws IOException {
public
int readUnsignedShort() throws IOException {
if (this.pointer + 2 > this.size) {
throw new EOFException();
}
@ -161,48 +167,54 @@ final class ClassFileBuffer implements DataInput {
}
@Override
public short readShort() throws IOException {
return (short)readUnsignedShort();
public
short readShort() throws IOException {
return (short) readUnsignedShort();
}
@Override
public char readChar() throws IOException {
return (char)readUnsignedShort();
public
char readChar() throws IOException {
return (char) readUnsignedShort();
}
@Override
public int readInt() throws IOException {
public
int readInt() throws IOException {
if (this.pointer + 4 > this.size) {
throw new EOFException();
}
return (read() << 24) +
(read() << 16) +
(read() << 8) +
read();
(read() << 16) +
(read() << 8) +
read();
}
@Override
public long readLong() throws IOException {
public
long readLong() throws IOException {
if (this.pointer + 8 > this.size) {
throw new EOFException();
}
return ((long)read() << 56) +
((long)read() << 48) +
((long)read() << 40) +
((long)read() << 32) +
(read() << 24) +
(read() << 16) +
(read() << 8) +
read();
return ((long) read() << 56) +
((long) read() << 48) +
((long) read() << 40) +
((long) read() << 32) +
(read() << 24) +
(read() << 16) +
(read() << 8) +
read();
}
@Override
public float readFloat() throws IOException {
public
float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
@Override
public double readDouble() throws IOException {
public
double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
@ -214,22 +226,26 @@ final class ClassFileBuffer implements DataInput {
*/
@Override
@Deprecated
public String readLine() throws IOException {
public
String readLine() throws IOException {
throw new UnsupportedOperationException("readLine() is deprecated and not supported");
}
@Override
public String readUTF() throws IOException {
public
String readUTF() throws IOException {
return DataInputStream.readUTF(this);
}
// private
private int read() {
private
int read() {
return this.buffer[this.pointer++] & 0xff;
}
private void resizeIfNeeded() {
private
void resizeIfNeeded() {
if (this.size >= this.buffer.length) {
final byte[] newBuffer = new byte[this.buffer.length * 2];
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);

View File

@ -21,22 +21,19 @@
*/
package dorkbox.util.annotation;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
/**
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
* a specific context.
* <p>
* <p/>
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
*
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @since annotation-detector 3.0.0
*/
public class ClassFileIterator implements ClassIterator {
public
class ClassFileIterator implements ClassIterator {
private FileIterator fileIter;
protected final String[] pkgNameFilter;
@ -47,24 +44,26 @@ public class ClassFileIterator implements ClassIterator {
/**
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
* 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
* defined package names are returned.
* 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;
}
/**
* Create a new {@code ClassFileIterator} returning all Java ClassFile files available
* 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
* defined package names are returned.
* 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.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.
*/
@Override
public String getName() {
public
String getName() {
// Both getPath() and getName() are very light weight method calls
return this.zipIter == null ?
this.fileIter.getFile().getPath() :
this.zipIter.getEntry().getName();
return this.zipIter == null ? this.fileIter.getFile().getPath() : this.zipIter.getEntry().getName();
}
/**
@ -88,37 +86,43 @@ public class ClassFileIterator implements ClassIterator {
* ZIP File Entry.
*/
@Override
public boolean isFile() {
public
boolean isFile() {
return this.isFile;
}
/**
* Return the next Java ClassFile as an {@code InputStream}.
* <p>
* <p/>
* NOTICE: Client code MUST close the returned {@code InputStream}!
*/
@Override
public InputStream next(final FilenameFilter filter) throws IOException {
public
InputStream next(final FilenameFilter filter) throws IOException {
while (true) {
if (this.zipIter == null) {
final File file = this.fileIter.next();
if (file == null) {
return null;
} else {
}
else {
final String path = file.getPath();
if (path.endsWith(".class") && (filter == null ||
filter.accept(this.fileIter.getRootFile(), this.fileIter.relativize(path)))) {
if (path.endsWith(".class") && (filter == null || filter.accept(this.fileIter.getRootFile(), this.fileIter.relativize(
path)))) {
this.isFile = true;
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);
} // else just ignore
}
} else {
}
else {
final InputStream is = this.zipIter.next(filter);
if (is == null) {
this.zipIter = null;
} else {
}
else {
this.isFile = false;
return is;
}
@ -128,7 +132,8 @@ public class ClassFileIterator implements ClassIterator {
// 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();
return value.regionMatches(true, value.length() - n, suffix, 0, n);
}

View File

@ -31,13 +31,14 @@ import java.io.InputStream;
/**
* {@code ClassFileIterator} is used to iterate over all Java ClassFile files available within
* a specific context.
* <p>
* <p/>
* For every Java ClassFile ({@code .class}) an {@link InputStream} is returned.
*
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @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()}.
@ -55,7 +56,7 @@ public interface ClassIterator {
/**
* Return the next Java ClassFile as an {@code InputStream}.
* <p>
* <p/>
* NOTICE: Client code MUST close the returned {@code InputStream}!
*/
InputStream next(final FilenameFilter filter) throws IOException;

View File

@ -33,7 +33,8 @@ import java.lang.reflect.Method;
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @since annotation-detector 3.1.0
*/
public interface Cursor {
public
interface Cursor {
/**
* Return the type name of the currently reported Java Class File.

View File

@ -15,6 +15,8 @@
*/
package dorkbox.util.annotation;
import dorkbox.util.FileUtil;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
@ -26,17 +28,17 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import dorkbox.util.FileUtil;
public
class CustomClassloaderIterator implements ClassIterator {
public class CustomClassloaderIterator implements ClassIterator {
private volatile Iterator<URL> loaderFilesIterator;
private final Iterator<URL> loaderFilesIterator;
private ClassFileIterator classFileIterator;
// have to support
// 1 - scanning the classpath
// 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)
Set<File> files = new HashSet<File>();
@ -56,7 +58,8 @@ public class CustomClassloaderIterator implements ClassIterator {
if (files.isEmpty()) {
this.classFileIterator = null;
} else {
}
else {
this.classFileIterator = new ClassFileIterator(files.toArray(new File[0]), packageNames);
}
@ -65,13 +68,15 @@ public class CustomClassloaderIterator implements ClassIterator {
}
@Override
public String getName() {
public
String getName() {
// not needed
return null;
}
@Override
public boolean isFile() {
public
boolean isFile() {
if (this.classFileIterator != null) {
return this.classFileIterator.isFile();
}
@ -80,13 +85,15 @@ public class CustomClassloaderIterator implements ClassIterator {
}
@Override
public InputStream next(FilenameFilter filter) throws IOException {
public
InputStream next(FilenameFilter filter) throws IOException {
if (this.classFileIterator != null) {
while (true) {
InputStream next = this.classFileIterator.next(filter);
if (next == null) {
this.classFileIterator = null;
} else {
}
else {
String name = this.classFileIterator.getName();
if (name.endsWith(".class")) {
return next;

View File

@ -29,7 +29,7 @@ import java.util.NoSuchElementException;
/**
* {@code FileIterator} enables iteration over all files in a directory and all its sub
* directories.
* <p>
* <p/>
* Usage:
* <pre>
* 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>
* @since annotation-detector 3.0.0
*/
final class FileIterator {
final
class FileIterator {
private final Deque<File> stack = new LinkedList<File>();
private int rootCount;
@ -52,13 +53,13 @@ final class FileIterator {
/**
* 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 directory, all files in that directory
* and its sub directories are returned (depth first).
*
* @param filesOrDirectories Zero or more {@link File} objects, which are iterated
* in the specified order (depth first)
* in the specified order (depth first)
*/
FileIterator(final File... filesOrDirectories) {
addReverse(filesOrDirectories);
@ -80,12 +81,12 @@ final class FileIterator {
/**
* Relativize the absolute full (file) 'path' against the current root file.
* <p>
* <p/>
* Example:<br/>
* Let current root be "/path/to/dir".
* Then {@code relativize("/path/to/dir/with/file.ext")} equals "with/file.ext" (without
* leading '/').
* <p>
* <p/>
* Note: the paths are not canonicalized!
*/
String relativize(final String path) {
@ -115,7 +116,8 @@ final class FileIterator {
if (this.stack.isEmpty()) {
this.current = null;
return null;
} else {
}
else {
this.current = this.stack.removeLast();
if (this.current.isDirectory()) {
if (this.stack.size() < this.rootCount) {
@ -124,7 +126,8 @@ final class FileIterator {
}
addReverse(this.current.listFiles());
return next();
} else {
}
else {
return this.current;
}
}
@ -135,7 +138,8 @@ final class FileIterator {
/**
* 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) {
this.stack.add(files[i]);
}

View File

@ -24,22 +24,21 @@ package dorkbox.util.annotation;
/**
* {@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
* 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>
* @see Builder#report(dorkbox.util.annotation.Reporter)
* @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
* provided {@code Cursor} reference to get more specific information about the
* {@code Annotation}.
*
*/
void report(Cursor cursor);

View File

@ -24,12 +24,12 @@ package dorkbox.util.annotation;
/**
* {@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>
* @see Builder#collect(dorkbox.util.annotation.ReporterFunction)
* @since annotation-detector 3.1.0
*/
public interface ReporterFunction<T> {
public
interface ReporterFunction<T> {
/**
* This method is called when an {@code Annotation} is detected.

View File

@ -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 jar} file and returning the {@link InputStream} of these entries.
* <p>
* <p/>
* 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.
*
* @author <a href="mailto:rmuller@xiam.nl">Ronald K. Muller</a>
* @since annotation-detector 3.0.0
*/
final class ZipFileIterator {
final
class ZipFileIterator {
private final File file;
private final ZipFile zipFile;
@ -52,9 +53,9 @@ final class ZipFileIterator {
/**
* Create a new {@code ZipFileIterator} instance.
*
* @param zipFile The ZIP file used to iterate over all entries
* @param zipFile The ZIP file used to iterate over all entries
* @param entryNameFilter (optional) file name filter. Only entry names starting with
* one of the specified names in the filter are returned
* one of the specified names in the filter are returned
*/
ZipFileIterator(final File file, final String[] entryNameFilter) throws IOException {
this.file = file;
@ -64,11 +65,13 @@ final class ZipFileIterator {
this.entries = this.zipFile.entries();
}
public ZipEntry getEntry() {
public
ZipEntry getEntry() {
return this.current;
}
public InputStream next(final FilenameFilter filter) throws IOException {
public
InputStream next(final FilenameFilter filter) throws IOException {
while (this.entries.hasMoreElements()) {
this.current = this.entries.nextElement();
if (filter == null || accept(this.current, filter)) {
@ -85,7 +88,8 @@ final class ZipFileIterator {
return null;
}
private boolean accept(final ZipEntry entry, final FilenameFilter filter) {
private
boolean accept(final ZipEntry entry, final FilenameFilter filter) {
if (entry.isDirectory()) {
return false;
}