PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/sisu-extender/src/main/java/com/atlassian/plugin/remotable/sisu/AbstractAnnotatedMethodTypeListener.java

https://bitbucket.org/rodogu/remotable-plugins
Java | 172 lines | 105 code | 18 blank | 49 comment | 8 complexity | 76cb2b43555cc1bbbd46b956eb4a802e MD5 | raw file
  1. package com.atlassian.plugin.remotable.sisu;
  2. /*
  3. * Copyright 2012 The 99 Software Foundation
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. import com.google.common.annotations.VisibleForTesting;
  18. import com.google.common.base.Function;
  19. import com.google.inject.TypeLiteral;
  20. import com.google.inject.spi.TypeEncounter;
  21. import com.google.inject.spi.TypeListener;
  22. import org.slf4j.Logger;
  23. import org.slf4j.LoggerFactory;
  24. import java.lang.annotation.Annotation;
  25. import java.lang.reflect.Method;
  26. import static com.atlassian.fugue.Option.option;
  27. import static com.atlassian.fugue.Suppliers.alwaysFalse;
  28. import static com.google.common.base.Preconditions.checkNotNull;
  29. /**
  30. * A Guice {@code TypeListener} to hear annotated methods with lifecycle annotations.
  31. */
  32. abstract class AbstractAnnotatedMethodTypeListener implements TypeListener
  33. {
  34. protected final Logger logger = LoggerFactory.getLogger(this.getClass());
  35. /**
  36. * The {@code java} package constants.
  37. */
  38. private static final String JAVA_PACKAGE = "java";
  39. /**
  40. * The lifecycle annotation to search on methods.
  41. */
  42. private final Class<? extends Annotation> annotationType;
  43. /**
  44. * Creates a new methods listener instance.
  45. *
  46. * @param annotationType the lifecycle annotation to search on methods.
  47. */
  48. public <A extends Annotation> AbstractAnnotatedMethodTypeListener(Class<A> annotationType)
  49. {
  50. this.annotationType = checkNotNull(annotationType);
  51. }
  52. /**
  53. * {@inheritDoc}
  54. */
  55. public final <I> void hear( TypeLiteral<I> type, TypeEncounter<I> encounter )
  56. {
  57. hear( type.getRawType(), encounter );
  58. }
  59. /**
  60. * Allows traverse the input type hierarchy.
  61. *
  62. * @param type encountered by Guice.
  63. * @param encounter the injection context.
  64. */
  65. private <I> void hear( Class<? super I> type, TypeEncounter<I> encounter )
  66. {
  67. logger.debug("Encountering type: {}", type);
  68. if ( type == null || isProxy(type) || isJdkType(type))
  69. {
  70. return;
  71. }
  72. for ( Method method : type.getDeclaredMethods() )
  73. {
  74. if ( method.isAnnotationPresent( annotationType ) )
  75. {
  76. if ( method.getParameterTypes().length != 0 )
  77. {
  78. encounter.addError( "Annotated methods with @%s must not accept any argument, found %s",
  79. annotationType.getName(), method );
  80. }
  81. hear( method, encounter );
  82. }
  83. }
  84. hear( type.getSuperclass(), encounter );
  85. }
  86. @VisibleForTesting
  87. boolean isProxy(final Class<?> type)
  88. {
  89. return option(type)
  90. .map(new Function<Class<?>, String>()
  91. {
  92. @Override
  93. public String apply(Class<?> type)
  94. {
  95. return type.getSimpleName();
  96. }
  97. })
  98. .fold(alwaysFalse(), new Function<String, Boolean>()
  99. {
  100. @Override
  101. public Boolean apply(String typeSimpleName)
  102. {
  103. final boolean isProxy = typeSimpleName.startsWith("$Proxy");
  104. logger.debug("Type '{}' is {} a proxy", type, isProxy ? "" : "NOT");
  105. return isProxy;
  106. }
  107. });
  108. }
  109. @VisibleForTesting
  110. boolean isJdkType(Class<?> type)
  111. {
  112. return option(type)
  113. .map(new Function<Class<?>, Package>()
  114. {
  115. @Override
  116. public Package apply(Class<?> type)
  117. {
  118. return type.getPackage();
  119. }
  120. })
  121. .map(new Function<Package, String>()
  122. {
  123. @Override
  124. public String apply(Package typePackage)
  125. {
  126. return typePackage.getName();
  127. }
  128. })
  129. .fold(alwaysFalse(), new Function<String, Boolean>()
  130. {
  131. @Override
  132. public Boolean apply(String packageName)
  133. {
  134. return packageName.startsWith(JAVA_PACKAGE);
  135. }
  136. });
  137. }
  138. /**
  139. * Returns the lifecycle annotation to search on methods.
  140. *
  141. * @return the lifecycle annotation to search on methods.
  142. */
  143. protected final Class<? extends Annotation> getAnnotationType()
  144. {
  145. return annotationType;
  146. }
  147. /**
  148. * Allows implementations to define the behavior when lifecycle annotation is found on the method.
  149. *
  150. * @param method encountered by this type handler.
  151. * @param encounter the injection context.
  152. */
  153. protected abstract <I> void hear( Method method, TypeEncounter<I> encounter );
  154. }