| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.annotations; |
| |
| import static org.hamcrest.Matchers.contains; |
| import static org.hamcrest.Matchers.notNullValue; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URL; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo; |
| import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo; |
| import org.eclipse.jetty.annotations.AnnotationParser.Handler; |
| import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo; |
| import org.eclipse.jetty.toolchain.test.FS; |
| import org.eclipse.jetty.toolchain.test.IO; |
| import org.eclipse.jetty.toolchain.test.MavenTestingUtils; |
| import org.eclipse.jetty.toolchain.test.TestingDir; |
| import org.junit.Assert; |
| import org.junit.Rule; |
| import org.junit.Test; |
| |
| public class TestAnnotationParser |
| { |
| public static class TrackingAnnotationHandler extends AnnotationParser.AbstractHandler |
| { |
| private final String annotationName; |
| public final Set<String> foundClasses; |
| |
| public TrackingAnnotationHandler(String annotationName) |
| { |
| this.annotationName = annotationName; |
| this.foundClasses = new HashSet<>(); |
| } |
| |
| @Override |
| public void handle(ClassInfo info, String annotation) |
| { |
| if (annotation == null || !annotationName.equals(annotation)) |
| return; |
| foundClasses.add(info.getClassName()); |
| } |
| } |
| |
| @Rule |
| public TestingDir testdir = new TestingDir(); |
| |
| @Test |
| public void testSampleAnnotation() throws Exception |
| { |
| String[] classNames = new String[] |
| { "org.eclipse.jetty.annotations.ClassA" }; |
| AnnotationParser parser = new AnnotationParser(); |
| |
| class SampleAnnotationHandler extends AnnotationParser.AbstractHandler |
| { |
| private List<String> methods = Arrays.asList("a","b","c","d","l"); |
| |
| public void handle(ClassInfo info, String annotation) |
| { |
| if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) |
| return; |
| |
| assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassName()); |
| } |
| |
| public void handle(FieldInfo info, String annotation) |
| { |
| if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) |
| return; |
| assertEquals("m",info.getFieldName()); |
| assertEquals(org.objectweb.asm.Type.OBJECT,org.objectweb.asm.Type.getType(info.getFieldType()).getSort()); |
| } |
| |
| public void handle(MethodInfo info, String annotation) |
| { |
| if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) |
| return; |
| assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassInfo().getClassName()); |
| assertTrue(methods.contains(info.getMethodName())); |
| assertEquals("org.eclipse.jetty.annotations.Sample",annotation); |
| } |
| } |
| |
| //long start = System.currentTimeMillis(); |
| parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver() |
| { |
| public boolean isExcluded(String name) |
| { |
| return false; |
| } |
| |
| public boolean shouldOverride(String name) |
| { |
| return false; |
| } |
| |
| }); |
| //long end = System.currentTimeMillis(); |
| |
| //System.err.println("Time to parse class: " + ((end - start))); |
| } |
| |
| @Test |
| public void testMultiAnnotation() throws Exception |
| { |
| String[] classNames = new String[] |
| { "org.eclipse.jetty.annotations.ClassB" }; |
| AnnotationParser parser = new AnnotationParser(); |
| |
| class MultiAnnotationHandler extends AnnotationParser.AbstractHandler |
| { |
| public void handle(ClassInfo info, String annotation) |
| { |
| if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation)) |
| return; |
| assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassName())); |
| } |
| |
| public void handle(FieldInfo info, String annotation) |
| { |
| if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation)) |
| return; |
| // there should not be any |
| fail(); |
| } |
| |
| public void handle(MethodInfo info, String annotation) |
| { |
| if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation)) |
| return; |
| assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassInfo().getClassName())); |
| assertTrue("a".equals(info.getMethodName())); |
| } |
| } |
| |
| parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null); |
| } |
| |
| @Test |
| public void testHiddenFilesInJar() throws Exception |
| { |
| File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); |
| AnnotationParser parser = new AnnotationParser(); |
| Set<Handler> emptySet = Collections.emptySet(); |
| parser.parse(emptySet, badClassesJar.toURI(),null); |
| // only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here |
| } |
| |
| @Test |
| public void testBasedirExclusion() throws Exception |
| { |
| // Build up basedir, which itself has a path segment that violates java package and classnaming. |
| // The basedir should have no effect on annotation scanning. |
| // Intentionally using a base director name that starts with a "." |
| // This mimics what you see in jenkins, hudson, hadoop, solr, camel, and selenium for their |
| // installed and/or managed webapps |
| File basedir = testdir.getPathFile(".base/workspace/classes").toFile(); |
| FS.ensureEmpty(basedir); |
| |
| // Copy in class that is known to have annotations. |
| copyClass(ClassA.class,basedir); |
| |
| // Setup Tracker |
| TrackingAnnotationHandler tracker = new TrackingAnnotationHandler(Sample.class.getName()); |
| |
| // Setup annotation scanning |
| AnnotationParser parser = new AnnotationParser(); |
| |
| // Parse |
| parser.parse(Collections.singleton(tracker), basedir.toURI(),null); |
| |
| // Validate |
| Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); |
| } |
| |
| private void copyClass(Class<?> clazz, File basedir) throws IOException |
| { |
| String classname = clazz.getName().replace('.',File.separatorChar) + ".class"; |
| URL url = this.getClass().getResource('/'+classname); |
| Assert.assertThat("URL for: " + classname,url,notNullValue()); |
| |
| String classpath = classname.substring(0,classname.lastIndexOf(File.separatorChar)); |
| FS.ensureDirExists(new File(basedir,classpath)); |
| |
| InputStream in = null; |
| OutputStream out = null; |
| try |
| { |
| in = url.openStream(); |
| out = new FileOutputStream(new File(basedir,classname)); |
| IO.copy(in,out); |
| } |
| finally |
| { |
| IO.close(out); |
| IO.close(in); |
| } |
| } |
| } |