summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlli Virtanen <olli.virtanen@oath.com>2018-06-07 15:19:59 +0200
committerOlli Virtanen <olli.virtanen@oath.com>2018-06-07 15:19:59 +0200
commitf35c4c3640e6bbf6d8de3630a857d54caceab932 (patch)
tree478e80e826f8727b5362afa533de7f7efd18f3c3
parent6d06cec92ab856c340e69a30cf0d11bf2972cd6b (diff)
Container-jersey2: convert Scala code to Java (take 2)
-rw-r--r--container-jersey2/pom.xml4
-rw-r--r--container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ComponentGraphProvider.java73
-rw-r--r--container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyApplication.java25
-rw-r--r--container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyServletProvider.java118
-rw-r--r--container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.java103
-rw-r--r--container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ComponentGraphProvider.scala40
-rw-r--r--container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyApplication.scala16
-rw-r--r--container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyServletProvider.scala109
-rw-r--r--container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.scala74
9 files changed, 319 insertions, 243 deletions
diff --git a/container-jersey2/pom.xml b/container-jersey2/pom.xml
index 76ff21dc028..c5ed7d872bf 100644
--- a/container-jersey2/pom.xml
+++ b/container-jersey2/pom.xml
@@ -53,10 +53,6 @@
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- </dependency>
</dependencies>
<build>
<plugins>
diff --git a/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ComponentGraphProvider.java b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ComponentGraphProvider.java
new file mode 100644
index 00000000000..7ff9646cb27
--- /dev/null
+++ b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ComponentGraphProvider.java
@@ -0,0 +1,73 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.servlet.jersey;
+
+import com.yahoo.container.di.config.ResolveDependencyException;
+import com.yahoo.container.di.config.RestApiContext;
+import com.yahoo.container.jaxrs.annotation.Component;
+import org.glassfish.hk2.api.Injectee;
+import org.glassfish.hk2.api.InjectionResolver;
+import org.glassfish.hk2.api.ServiceHandle;
+
+import javax.inject.Singleton;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Resolves jdisc container components for jersey 2 components.
+ *
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+@Singleton // jersey2 requirement: InjectionResolvers must be in the Singleton scope
+public class ComponentGraphProvider implements InjectionResolver<Component> {
+ private Collection<RestApiContext.Injectable> injectables;
+
+ public ComponentGraphProvider(Collection<RestApiContext.Injectable> injectables) {
+ this.injectables = injectables;
+ }
+
+ @Override
+ public Object resolve(Injectee injectee, ServiceHandle<?> root) {
+ Class<?> wantedClass;
+ Type type = injectee.getRequiredType();
+ if (type instanceof Class) {
+ wantedClass = (Class<?>) type;
+ } else {
+ throw new UnsupportedOperationException("Only classes are supported, got " + type);
+ }
+
+ List<RestApiContext.Injectable> componentsWithMatchingType = new ArrayList<>();
+ for (RestApiContext.Injectable injectable : injectables) {
+ if (wantedClass.isInstance(injectable.instance)) {
+ componentsWithMatchingType.add(injectable);
+ }
+ }
+
+ if (componentsWithMatchingType.size() == 1) {
+ return componentsWithMatchingType.get(0).instance;
+ } else {
+ String injectionDescription = "class '" + wantedClass + "' to inject into Jersey resource/provider '"
+ + injectee.getInjecteeClass() + "')";
+ if (componentsWithMatchingType.size() > 1) {
+ String ids = componentsWithMatchingType.stream().map(c -> c.id.toString()).collect(Collectors.joining(","));
+ throw new ResolveDependencyException("Multiple components found of " + injectionDescription + ": " + ids);
+ } else {
+ throw new ResolveDependencyException("Could not find a component of " + injectionDescription + ".");
+ }
+ }
+ }
+
+ @Override
+ public boolean isMethodParameterIndicator() {
+ return true;
+ }
+
+ @Override
+ public boolean isConstructorParameterIndicator() {
+ return true;
+ }
+}
diff --git a/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyApplication.java b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyApplication.java
new file mode 100644
index 00000000000..4c4e43bc8d5
--- /dev/null
+++ b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyApplication.java
@@ -0,0 +1,25 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.servlet.jersey;
+
+import javax.ws.rs.core.Application;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class JerseyApplication extends Application {
+ private Set<Class<?>> classes;
+
+ public JerseyApplication(Collection<Class<?>> resourcesAndProviderClasses) {
+ this.classes = new HashSet<>(resourcesAndProviderClasses);
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return classes;
+ }
+}
diff --git a/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyServletProvider.java b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyServletProvider.java
new file mode 100644
index 00000000000..1dbe410ba54
--- /dev/null
+++ b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/JerseyServletProvider.java
@@ -0,0 +1,118 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.servlet.jersey;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import com.yahoo.container.di.componentgraph.Provider;
+import com.yahoo.container.di.config.RestApiContext;
+import com.yahoo.container.di.config.RestApiContext.BundleInfo;
+import com.yahoo.container.jaxrs.annotation.Component;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.glassfish.hk2.api.InjectionResolver;
+import org.glassfish.hk2.api.TypeLiteral;
+import org.glassfish.hk2.utilities.Binder;
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletContainer;
+import org.objectweb.asm.ClassReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import static com.yahoo.container.servlet.jersey.util.ResourceConfigUtil.registerComponent;
+
+/**
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class JerseyServletProvider implements Provider<ServletHolder> {
+ private final ServletHolder jerseyServletHolder;
+
+ public JerseyServletProvider(RestApiContext restApiContext) {
+ this.jerseyServletHolder = new ServletHolder(new ServletContainer(resourceConfig(restApiContext)));
+ }
+
+ private ResourceConfig resourceConfig(RestApiContext restApiContext) {
+ final ResourceConfig resourceConfig = ResourceConfig
+ .forApplication(new JerseyApplication(resourcesAndProviders(restApiContext.getBundles())));
+
+ registerComponent(resourceConfig, componentInjectorBinder(restApiContext));
+ registerComponent(resourceConfig, jacksonDatatypeJdk8Provider());
+ resourceConfig.register(MultiPartFeature.class);
+
+ return resourceConfig;
+ }
+
+ private static Collection<Class<?>> resourcesAndProviders(Collection<BundleInfo> bundles) {
+ final List<Class<?>> ret = new ArrayList<>();
+
+ for (BundleInfo bundle : bundles) {
+ for (String classEntry : bundle.getClassEntries()) {
+ Optional<String> className = detectResourceOrProvider(bundle.classLoader, classEntry);
+ className.ifPresent(cname -> ret.add(loadClass(bundle.symbolicName, bundle.classLoader, cname)));
+ }
+ }
+ return ret;
+ }
+
+ private static Optional<String> detectResourceOrProvider(ClassLoader bundleClassLoader, String classEntry) {
+ try (InputStream inputStream = getResourceAsStream(bundleClassLoader, classEntry)) {
+ ResourceOrProviderClassVisitor visitor = ResourceOrProviderClassVisitor.visit(new ClassReader(inputStream));
+ return visitor.getJerseyClassName();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static InputStream getResourceAsStream(ClassLoader bundleClassLoader, String classEntry) {
+ InputStream is = bundleClassLoader.getResourceAsStream(classEntry);
+ if (is == null) {
+ throw new RuntimeException("No entry " + classEntry + " in bundle " + bundleClassLoader);
+ } else {
+ return is;
+ }
+ }
+
+ private static Class<?> loadClass(String bundleSymbolicName, ClassLoader classLoader, String className) {
+ try {
+ return classLoader.loadClass(className);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed loading class " + className + " from bundle " + bundleSymbolicName, e);
+ }
+ }
+
+ private static Binder componentInjectorBinder(RestApiContext restApiContext) {
+ final ComponentGraphProvider componentGraphProvider = new ComponentGraphProvider(restApiContext.getInjectableComponents());
+ final TypeLiteral<InjectionResolver<Component>> componentAnnotationType = new TypeLiteral<InjectionResolver<Component>>() {
+ };
+
+ return new AbstractBinder() {
+ @Override
+ public void configure() {
+ bind(componentGraphProvider).to(componentAnnotationType);
+ }
+ };
+ }
+
+ private static JacksonJaxbJsonProvider jacksonDatatypeJdk8Provider() {
+ JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
+ provider.setMapper(new ObjectMapper().registerModule(new Jdk8Module()).registerModule(new JavaTimeModule()));
+ return provider;
+ }
+
+ @Override
+ public ServletHolder get() {
+ return jerseyServletHolder;
+ }
+
+ @Override
+ public void deconstruct() {
+ }
+}
diff --git a/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.java b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.java
new file mode 100644
index 00000000000..7cb47ac6118
--- /dev/null
+++ b/container-jersey2/src/main/java/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.java
@@ -0,0 +1,103 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.servlet.jersey;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.ext.Provider;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * @author Tony Vaagenes
+ * @author ollivir
+ */
+public class ResourceOrProviderClassVisitor extends ClassVisitor {
+ private String className = null;
+ private boolean isPublic = false;
+ private boolean isAbstract = false;
+
+ private boolean isInnerClass = false;
+ private boolean isStatic = false;
+
+ private boolean isAnnotated = false;
+
+ public ResourceOrProviderClassVisitor() {
+ super(Opcodes.ASM6);
+ }
+
+ public Optional<String> getJerseyClassName() {
+ if (isJerseyClass()) {
+ return Optional.of(getClassName());
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ public boolean isJerseyClass() {
+ return isAnnotated && isPublic && !isAbstract && (!isInnerClass || isStatic);
+ }
+
+ public String getClassName() {
+ assert (className != null);
+ return org.objectweb.asm.Type.getObjectType(className).getClassName();
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ isPublic = isPublic(access);
+ className = name;
+ isAbstract = isAbstract(access);
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ assert (className != null);
+
+ if (name.equals(className)) {
+ isInnerClass = true;
+ isStatic = isStatic(access);
+ }
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ isAnnotated |= annotationClassDescriptors.contains(desc);
+ return null;
+ }
+
+ private static Set<String> annotationClassDescriptors = new HashSet<>();
+
+ static {
+ annotationClassDescriptors.add(Type.getDescriptor(Path.class));
+ annotationClassDescriptors.add(Type.getDescriptor(Provider.class));
+ }
+
+ private static boolean isPublic(int access) {
+ return isSet(Opcodes.ACC_PUBLIC, access);
+ }
+
+ private static boolean isStatic(int access) {
+ return isSet(Opcodes.ACC_STATIC, access);
+ }
+
+ private static boolean isAbstract(int access) {
+ return isSet(Opcodes.ACC_ABSTRACT, access);
+ }
+
+ private static boolean isSet(int bits, int access) {
+ return (access & bits) == bits;
+ }
+
+ public static ResourceOrProviderClassVisitor visit(ClassReader classReader) {
+ ResourceOrProviderClassVisitor visitor = new ResourceOrProviderClassVisitor();
+ classReader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
+ return visitor;
+ }
+}
diff --git a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ComponentGraphProvider.scala b/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ComponentGraphProvider.scala
deleted file mode 100644
index cabde3680a4..00000000000
--- a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ComponentGraphProvider.scala
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.servlet.jersey
-
-import javax.inject.Singleton
-
-import com.yahoo.container.di.config.{ResolveDependencyException, RestApiContext}
-import com.yahoo.container.jaxrs.annotation.Component
-import org.glassfish.hk2.api.{ServiceHandle, Injectee, InjectionResolver}
-
-/**
- * Resolves jdisc container components for jersey 2 components.
- * Similar to Gjoran's ComponentGraphProvider for jersey 1.
- * @author tonytv
- */
-@Singleton //jersey2 requirement: InjectionResolvers must be in the Singleton scope
-class ComponentGraphProvider(injectables: Traversable[RestApiContext.Injectable]) extends InjectionResolver[Component] {
- override def resolve(injectee: Injectee, root: ServiceHandle[_]): AnyRef = {
- val wantedClass = injectee.getRequiredType match {
- case c: Class[_] => c
- case unsupported => throw new UnsupportedOperationException("Only classes are supported, got " + unsupported)
- }
-
- val componentsWithMatchingType = injectables.filter{ injectable =>
- wantedClass.isInstance(injectable.instance) }
-
- val injectionDescription =
- s"class '$wantedClass' to inject into Jersey resource/provider '${injectee.getInjecteeClass}')"
-
- if (componentsWithMatchingType.size > 1)
- throw new ResolveDependencyException(s"Multiple components found of $injectionDescription: " +
- componentsWithMatchingType.map(_.id).mkString(","))
-
- componentsWithMatchingType.headOption.map(_.instance).getOrElse {
- throw new ResolveDependencyException(s"Could not find a component of $injectionDescription.")
- }
- }
-
- override def isMethodParameterIndicator: Boolean = true
- override def isConstructorParameterIndicator: Boolean = true
-}
diff --git a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyApplication.scala b/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyApplication.scala
deleted file mode 100644
index eea41003984..00000000000
--- a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyApplication.scala
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.servlet.jersey
-
-import javax.ws.rs.core.Application
-
-import scala.collection.JavaConverters._
-
-/**
- * @author tonytv
- */
-class JerseyApplication(resourcesAndProviderClasses: Set[Class[_]]) extends Application {
- private val classes: java.util.Set[Class[_]] = resourcesAndProviderClasses.asJava
-
- override def getClasses = classes
- override def getSingletons = super.getSingletons
-}
diff --git a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyServletProvider.scala b/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyServletProvider.scala
deleted file mode 100644
index f0eff54dc16..00000000000
--- a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/JerseyServletProvider.scala
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.servlet.jersey
-
-import java.io.{IOException, InputStream}
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
-import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider
-import com.yahoo.container.di.componentgraph.Provider
-import com.yahoo.container.di.config.RestApiContext
-import com.yahoo.container.di.config.RestApiContext.BundleInfo
-import com.yahoo.container.jaxrs.annotation.Component
-import com.yahoo.container.servlet.jersey.util.ResourceConfigUtil.registerComponent
-import org.eclipse.jetty.servlet.ServletHolder
-import org.glassfish.hk2.api.{InjectionResolver, TypeLiteral}
-import org.glassfish.hk2.utilities.Binder
-import org.glassfish.hk2.utilities.binding.AbstractBinder
-import org.glassfish.jersey.media.multipart.MultiPartFeature
-import org.glassfish.jersey.server.ResourceConfig
-import org.glassfish.jersey.servlet.ServletContainer
-import org.objectweb.asm.ClassReader
-
-import scala.collection.JavaConverters._
-import scala.util.control.Exception
-
-
-/**
- * @author tonytv
- */
-class JerseyServletProvider(restApiContext: RestApiContext) extends Provider[ServletHolder] {
- private val jerseyServletHolder = new ServletHolder(new ServletContainer(resourceConfig(restApiContext)))
-
- private def resourceConfig(restApiContext: RestApiContext) = {
- val resourceConfig = ResourceConfig.forApplication(
- new JerseyApplication(resourcesAndProviders(restApiContext.getBundles.asScala)))
-
- registerComponent(resourceConfig, componentInjectorBinder(restApiContext))
- registerComponent(resourceConfig, jacksonDatatypeJdk8Provider)
- resourceConfig.register(classOf[MultiPartFeature])
-
- resourceConfig
- }
-
- def resourcesAndProviders(bundles: Traversable[BundleInfo]) =
- (for {
- bundle <- bundles.view
- classEntry <- bundle.getClassEntries.asScala
- className <- detectResourceOrProvider(bundle.classLoader, classEntry)
- } yield loadClass(bundle.symbolicName, bundle.classLoader, className)).toSet
-
-
- def detectResourceOrProvider(bundleClassLoader: ClassLoader, classEntry: String): Option[String] = {
- using(getResourceAsStream(bundleClassLoader, classEntry)) { inputStream =>
- val visitor = ResourceOrProviderClassVisitor.visit(new ClassReader(inputStream))
- visitor.getJerseyClassName
- }
- }
-
- private def getResourceAsStream(bundleClassLoader: ClassLoader, classEntry: String) = {
- bundleClassLoader.getResourceAsStream(classEntry) match {
- case null => throw new RuntimeException(s"No entry $classEntry in bundle $bundleClassLoader")
- case stream => stream
- }
-
- }
-
- def using[T <: InputStream, R](stream: T)(f: T => R): R = {
- try {
- f(stream)
- } finally {
- Exception.ignoring(classOf[IOException]) {
- stream.close()
- }
- }
- }
-
- def loadClass(bundleSymbolicName: String, classLoader: ClassLoader, className: String) = {
- try {
- classLoader.loadClass(className)
- } catch {
- case e: Exception => throw new RuntimeException(s"Failed loading class $className from bundle $bundleSymbolicName", e)
- }
- }
-
- def componentInjectorBinder(restApiContext: RestApiContext): Binder = {
- val componentGraphProvider = new ComponentGraphProvider(restApiContext.getInjectableComponents.asScala)
- val componentAnnotationType = new TypeLiteral[InjectionResolver[Component]] {}
-
- new AbstractBinder {
- override def configure() {
- bind(componentGraphProvider).to(componentAnnotationType)
- }
- }
- }
-
- def jacksonDatatypeJdk8Provider: JacksonJaxbJsonProvider = {
- val provider = new JacksonJaxbJsonProvider()
- provider.setMapper(
- new ObjectMapper()
- .registerModule(new Jdk8Module)
- .registerModule(new JavaTimeModule))
- provider
- }
-
- override def get() = jerseyServletHolder
- override def deconstruct() {}
-}
-
diff --git a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.scala b/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.scala
deleted file mode 100644
index 52674026c25..00000000000
--- a/container-jersey2/src/main/scala/com/yahoo/container/servlet/jersey/ResourceOrProviderClassVisitor.scala
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.servlet.jersey
-
-import javax.ws.rs.Path
-import javax.ws.rs.ext.Provider
-
-import org.objectweb.asm.{ClassVisitor, Opcodes, Type, AnnotationVisitor, ClassReader}
-
-
-/**
- * @author tonytv
- */
-class ResourceOrProviderClassVisitor private () extends ClassVisitor(Opcodes.ASM6) {
- private var className: String = null
- private var isPublic: Boolean = false
- private var isAbstract = false
-
- private var isInnerClass: Boolean = false
- private var isStatic: Boolean = false
-
- private var isAnnotated: Boolean = false
-
- def getJerseyClassName: Option[String] = {
- if (isJerseyClass) Some(getClassName)
- else None
- }
-
- def isJerseyClass: Boolean = {
- isAnnotated && isPublic && !isAbstract &&
- (!isInnerClass || isStatic)
- }
-
- def getClassName = {
- assert (className != null)
- Type.getObjectType(className).getClassName
- }
-
- override def visit(version: Int, access: Int, name: String, signature: String, superName: String, interfaces: Array[String]) {
- isPublic = ResourceOrProviderClassVisitor.isPublic(access)
- className = name
- isAbstract = ResourceOrProviderClassVisitor.isAbstract(access)
- }
-
- override def visitInnerClass(name: String, outerName: String, innerName: String, access: Int) {
- assert (className != null)
-
- if (name == className) {
- isInnerClass = true
- isStatic = ResourceOrProviderClassVisitor.isStatic(access)
- }
- }
-
- override def visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor = {
- isAnnotated |= ResourceOrProviderClassVisitor.annotationClassDescriptors(desc)
- null
- }
-}
-
-
-object ResourceOrProviderClassVisitor {
- val annotationClassDescriptors = Set(classOf[Path], classOf[Provider]) map Type.getDescriptor
-
- def isPublic = isSet(Opcodes.ACC_PUBLIC) _
- def isStatic = isSet(Opcodes.ACC_STATIC) _
- def isAbstract = isSet(Opcodes.ACC_ABSTRACT) _
-
- private def isSet(bits: Int)(access: Int): Boolean = (access & bits) == bits
-
- def visit(classReader: ClassReader): ResourceOrProviderClassVisitor = {
- val visitor = new ResourceOrProviderClassVisitor
- classReader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES)
- visitor
- }
-}