Consistent support for Java 8 default methods (in interfaces implemented by user classes)
Covers ReflectionUtils.doWithMethods as well as affected annotation post-processors. Includes an extension of MethodMetadata for the detection of @Bean default methods. Issue: SPR-12822 Issue: SPR-10919
This commit is contained in:
parent
778a01943b
commit
192462902e
|
@ -380,48 +380,58 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
|||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
|
||||
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
do {
|
||||
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
for (Field field : targetClass.getDeclaredFields()) {
|
||||
AnnotationAttributes ann = findAutowiredAnnotation(field);
|
||||
if (ann != null) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static fields: " + field);
|
||||
final LinkedList<InjectionMetadata.InjectedElement> currElements =
|
||||
new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
|
||||
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
AnnotationAttributes ann = findAutowiredAnnotation(field);
|
||||
if (ann != null) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static fields: " + field);
|
||||
}
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
currElements.add(new AutowiredFieldElement(field, required));
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
currElements.add(new AutowiredFieldElement(field, required));
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
continue;
|
||||
}
|
||||
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
|
||||
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static methods: " + method);
|
||||
});
|
||||
|
||||
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
return;
|
||||
}
|
||||
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
|
||||
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static methods: " + method);
|
||||
}
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation should be used on methods with parameters: " + method);
|
||||
}
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new AutowiredMethodElement(method, required, pd));
|
||||
}
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new AutowiredMethodElement(method, required, pd));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elements.addAll(0, currElements);
|
||||
targetClass = targetClass.getSuperclass();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -187,34 +187,39 @@ public class InitDestroyAnnotationBeanPostProcessor
|
|||
return metadata;
|
||||
}
|
||||
|
||||
private LifecycleMetadata buildLifecycleMetadata(Class<?> clazz) {
|
||||
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
|
||||
LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
do {
|
||||
LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
|
||||
LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
if (this.initAnnotationType != null) {
|
||||
if (method.getAnnotation(this.initAnnotationType) != null) {
|
||||
LifecycleElement element = new LifecycleElement(method);
|
||||
currInitMethods.add(element);
|
||||
if (debug) {
|
||||
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
|
||||
final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
|
||||
final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
|
||||
|
||||
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (initAnnotationType != null) {
|
||||
if (method.getAnnotation(initAnnotationType) != null) {
|
||||
LifecycleElement element = new LifecycleElement(method);
|
||||
currInitMethods.add(element);
|
||||
if (debug) {
|
||||
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (destroyAnnotationType != null) {
|
||||
if (method.getAnnotation(destroyAnnotationType) != null) {
|
||||
currDestroyMethods.add(new LifecycleElement(method));
|
||||
if (debug) {
|
||||
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.destroyAnnotationType != null) {
|
||||
if (method.getAnnotation(this.destroyAnnotationType) != null) {
|
||||
currDestroyMethods.add(new LifecycleElement(method));
|
||||
if (debug) {
|
||||
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
initMethods.addAll(0, currInitMethods);
|
||||
destroyMethods.addAll(currDestroyMethods);
|
||||
targetClass = targetClass.getSuperclass();
|
||||
|
|
|
@ -189,6 +189,32 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedResourceInjectionWithDefaultMethod() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerResolvableDependency(BeanFactory.class, bf);
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
RootBeanDefinition annotatedBd = new RootBeanDefinition(DefaultMethodResourceInjectionBean.class);
|
||||
bf.registerBeanDefinition("annotatedBean", annotatedBd);
|
||||
TestBean tb = new TestBean();
|
||||
bf.registerSingleton("testBean", tb);
|
||||
NestedTestBean ntb = new NestedTestBean();
|
||||
bf.registerSingleton("nestedTestBean", ntb);
|
||||
|
||||
DefaultMethodResourceInjectionBean bean = (DefaultMethodResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(tb, bean.getTestBean());
|
||||
assertNull(bean.getTestBean2());
|
||||
assertSame(tb, bean.getTestBean3());
|
||||
assertSame(tb, bean.getTestBean4());
|
||||
assertSame(ntb, bean.getNestedTestBean());
|
||||
assertNull(bean.getBeanFactory());
|
||||
assertTrue(bean.baseInjected);
|
||||
assertTrue(bean.subInjected);
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedResourceInjectionWithAtRequired() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
@ -1876,6 +1902,42 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
}
|
||||
|
||||
|
||||
public interface InterfaceWithDefaultMethod {
|
||||
|
||||
@Autowired
|
||||
void setTestBean2(TestBean testBean2);
|
||||
|
||||
@Autowired
|
||||
default void injectDefault(ITestBean testBean4) {
|
||||
markSubInjected();
|
||||
}
|
||||
|
||||
void markSubInjected();
|
||||
}
|
||||
|
||||
|
||||
public static class DefaultMethodResourceInjectionBean extends NonPublicResourceInjectionBean<NestedTestBean>
|
||||
implements InterfaceWithDefaultMethod {
|
||||
|
||||
public boolean subInjected = false;
|
||||
|
||||
@Override
|
||||
public void setTestBean2(TestBean testBean2) {
|
||||
super.setTestBean2(testBean2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markSubInjected() {
|
||||
subInjected = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class OptionalResourceInjectionBean extends ResourceInjectionBean {
|
||||
|
||||
@Autowired(required = false)
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.springframework.core.Ordered;
|
|||
import org.springframework.jndi.support.SimpleJndiBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -339,75 +340,85 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
|
|||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
|
||||
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
do {
|
||||
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
for (Field field : targetClass.getDeclaredFields()) {
|
||||
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
|
||||
final LinkedList<InjectionMetadata.InjectedElement> currElements =
|
||||
new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
|
||||
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
|
||||
}
|
||||
currElements.add(new WebServiceRefElement(field, field, null));
|
||||
}
|
||||
currElements.add(new WebServiceRefElement(field, field, null));
|
||||
}
|
||||
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static fields");
|
||||
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static fields");
|
||||
}
|
||||
currElements.add(new EjbRefElement(field, field, null));
|
||||
}
|
||||
currElements.add(new EjbRefElement(field, field, null));
|
||||
}
|
||||
else if (field.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static fields");
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(field.getType().getName())) {
|
||||
currElements.add(new ResourceElement(field, field, null));
|
||||
else if (field.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static fields");
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(field.getType().getName())) {
|
||||
currElements.add(new ResourceElement(field, field, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
continue;
|
||||
}
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
|
||||
});
|
||||
|
||||
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
return;
|
||||
}
|
||||
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
|
||||
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new ResourceElement(method, bridgedMethod, pd));
|
||||
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@EJB annotation is not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
|
||||
}
|
||||
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@Resource annotation is not supported on static methods");
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
|
||||
}
|
||||
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new ResourceElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elements.addAll(0, currElements);
|
||||
targetClass = targetClass.getSuperclass();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -288,6 +288,17 @@ class ConfigurationClassParser {
|
|||
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
|
||||
}
|
||||
|
||||
// Process default methods on interfaces
|
||||
for (SourceClass ifc : sourceClass.getInterfaces()) {
|
||||
beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
|
||||
for (MethodMetadata methodMetadata : beanMethods) {
|
||||
if (!methodMetadata.isAbstract()) {
|
||||
// A default method or other concrete method on a Java 8+ interface...
|
||||
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process superclass, if any
|
||||
if (sourceClass.getMetadata().hasSuperClass()) {
|
||||
String superclass = sourceClass.getMetadata().getSuperClassName();
|
||||
|
@ -474,7 +485,7 @@ class ConfigurationClassParser {
|
|||
}
|
||||
else {
|
||||
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
|
||||
// process it as a @Configuration class
|
||||
// process it as an @Configuration class
|
||||
this.importStack.registerImport(
|
||||
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
|
||||
processConfigurationClass(candidate.asConfigClass(configClass));
|
||||
|
@ -762,6 +773,22 @@ class ConfigurationClassParser {
|
|||
return asSourceClass(((MetadataReader) this.source).getClassMetadata().getSuperClassName());
|
||||
}
|
||||
|
||||
public Set<SourceClass> getInterfaces() throws IOException {
|
||||
Set<SourceClass> result = new LinkedHashSet<SourceClass>();
|
||||
if (this.source instanceof Class<?>) {
|
||||
Class<?> sourceClass = (Class<?>) this.source;
|
||||
for (Class<?> ifcClass : sourceClass.getInterfaces()) {
|
||||
result.add(asSourceClass(ifcClass));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (String className : this.metadata.getInterfaceNames()) {
|
||||
result.add(asSourceClass(className));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Set<SourceClass> getAnnotations() throws IOException {
|
||||
Set<SourceClass> result = new LinkedHashSet<SourceClass>();
|
||||
for (String className : this.metadata.getAnnotationTypes()) {
|
||||
|
|
|
@ -243,6 +243,26 @@ public class CommonAnnotationBeanPostProcessorTests {
|
|||
assertEquals("testBean4", depBeans[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceInjectionWithDefaultMethod() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(DefaultMethodResourceInjectionBean.class));
|
||||
TestBean tb2 = new TestBean();
|
||||
bf.registerSingleton("testBean2", tb2);
|
||||
NestedTestBean tb7 = new NestedTestBean();
|
||||
bf.registerSingleton("testBean7", tb7);
|
||||
|
||||
DefaultMethodResourceInjectionBean bean = (DefaultMethodResourceInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(tb2, bean.getTestBean2());
|
||||
assertSame(2, bean.counter);
|
||||
|
||||
bf.destroySingletons();
|
||||
assertSame(3, bean.counter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceInjectionWithTwoProcessors() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
@ -694,6 +714,42 @@ public class CommonAnnotationBeanPostProcessorTests {
|
|||
}
|
||||
|
||||
|
||||
public interface InterfaceWithDefaultMethod {
|
||||
|
||||
@Resource
|
||||
void setTestBean2(TestBean testBean2);
|
||||
|
||||
@Resource
|
||||
default void setTestBean7(INestedTestBean testBean7) {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
default void initDefault() {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
default void destroyDefault() {
|
||||
increaseCounter();
|
||||
}
|
||||
|
||||
void increaseCounter();
|
||||
}
|
||||
|
||||
|
||||
public static class DefaultMethodResourceInjectionBean extends ResourceInjectionBean
|
||||
implements InterfaceWithDefaultMethod {
|
||||
|
||||
public int counter = 0;
|
||||
|
||||
@Override
|
||||
public void increaseCounter() {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ExtendedEjbInjectionBean extends ResourceInjectionBean {
|
||||
|
||||
@EJB(name="testBean4", beanInterface=TestBean.class)
|
||||
|
|
|
@ -470,6 +470,36 @@ public class ConfigurationClassPostProcessorTests {
|
|||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethods() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfigWithDefaultMethods.class));
|
||||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigWithDefaultMethodsUsingAsm() {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(beanFactory);
|
||||
beanFactory.addBeanPostProcessor(bpp);
|
||||
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
|
||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfigWithDefaultMethods.class.getName()));
|
||||
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class.getName()));
|
||||
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||
beanFactory.preInstantiateSingletons();
|
||||
|
||||
beanFactory.getBean(ServiceBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -944,6 +974,37 @@ public class ConfigurationClassPostProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
public interface DefaultMethodsConfig {
|
||||
|
||||
@Bean
|
||||
default ServiceBean serviceBean() {
|
||||
return provider().getServiceBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
default ServiceBeanProvider provider() {
|
||||
return new ServiceBeanProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class ConcreteConfigWithDefaultMethods implements DefaultMethodsConfig {
|
||||
|
||||
@Autowired
|
||||
private ServiceBeanProvider provider;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ServiceBeanProvider provider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void validate() {
|
||||
Assert.notNull(provider);
|
||||
}
|
||||
}
|
||||
|
||||
@Primary
|
||||
public static class ServiceBeanProvider {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -77,6 +77,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -98,11 +99,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test
|
||||
public void fixedRateTask() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.FixedRateTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -128,6 +129,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -148,19 +150,29 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
|
||||
@Test
|
||||
public void severalFixedRatesWithRepeatedScheduledAnnotation() {
|
||||
BeanDefinition processorDefinition = new
|
||||
RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesWithSchedulesContainerAnnotation() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
SeveralFixedRatesWithSchedulesContainerAnnotationTestBean.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(SeveralFixedRatesWithSchedulesContainerAnnotationTestBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesOnBaseClass() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesSubBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalFixedRatesOnDefaultMethod() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRatesDefaultBean.class);
|
||||
severalFixedRates(context, processorDefinition, targetDefinition);
|
||||
}
|
||||
|
||||
|
@ -170,6 +182,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -201,11 +214,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -229,11 +242,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronWithTimezoneTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithTimezoneTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -274,8 +287,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
Assume.group(TestGroup.LONG_RUNNING);
|
||||
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronWithInvalidTimezoneTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronWithInvalidTimezoneTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
@ -286,8 +298,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
public void cronTaskWithMethodValidation() throws InterruptedException {
|
||||
BeanDefinition validationDefinition = new RootBeanDefinition(MethodValidationPostProcessor.class);
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.CronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(CronTestBean.class);
|
||||
context.registerBeanDefinition("methodValidation", validationDefinition);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
|
@ -301,6 +312,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -321,11 +333,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test
|
||||
public void metaAnnotationWithCronExpression() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.MetaAnnotationCronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationCronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -356,6 +368,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -386,6 +399,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -417,6 +431,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -443,12 +458,12 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
Properties properties = new Properties();
|
||||
properties.setProperty("schedules.businessHours", businessHoursCronExpression);
|
||||
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.PropertyPlaceholderMetaAnnotationTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderMetaAnnotationTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
||||
Object postProcessor = context.getBean("postProcessor");
|
||||
Object target = context.getBean("target");
|
||||
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||
|
@ -469,8 +484,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test(expected = BeanCreationException.class)
|
||||
public void emptyAnnotation() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.EmptyAnnotationTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(EmptyAnnotationTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
@ -479,8 +493,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test(expected = BeanCreationException.class)
|
||||
public void invalidCron() throws Throwable {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.InvalidCronTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(InvalidCronTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
@ -489,8 +502,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test(expected = BeanCreationException.class)
|
||||
public void nonVoidReturnType() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.NonVoidReturnTypeTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(NonVoidReturnTypeTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
@ -499,8 +511,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
@Test(expected = BeanCreationException.class)
|
||||
public void nonEmptyParamList() {
|
||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
||||
ScheduledAnnotationBeanPostProcessorTests.NonEmptyParamListTestBean.class);
|
||||
BeanDefinition targetDefinition = new RootBeanDefinition(NonEmptyParamListTestBean.class);
|
||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||
context.registerBeanDefinition("target", targetDefinition);
|
||||
context.refresh();
|
||||
|
@ -542,16 +553,39 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
|||
|
||||
static class SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean {
|
||||
|
||||
// can use Java 8 repeated @Scheduled once we have Eclipse IDE support for it
|
||||
@Schedules({
|
||||
@Scheduled(fixedRate=4000),
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
})
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
public void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesBaseBean {
|
||||
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
public void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesSubBean extends FixedRatesBaseBean {
|
||||
}
|
||||
|
||||
|
||||
static interface FixedRatesDefaultMethod {
|
||||
|
||||
@Scheduled(fixedRate=4000)
|
||||
@Scheduled(fixedRate=4000, initialDelay=2000)
|
||||
default void fixedRate() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class FixedRatesDefaultBean implements FixedRatesDefaultMethod {
|
||||
}
|
||||
|
||||
|
||||
@Validated
|
||||
static class CronTestBean {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -41,6 +41,14 @@ public interface MethodMetadata extends AnnotatedTypeMetadata {
|
|||
*/
|
||||
public String getDeclaringClassName();
|
||||
|
||||
/**
|
||||
* Return whether the underlying method is effectively abstract:
|
||||
* i.e. marked as abstract on a class or declared as a regular,
|
||||
* non-default method in an interface.
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean isAbstract();
|
||||
|
||||
/**
|
||||
* Return whether the underlying method is declared as 'static'.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -84,6 +84,11 @@ public class StandardMethodMetadata implements MethodMetadata {
|
|||
return this.introspectedMethod.getDeclaringClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstract() {
|
||||
return Modifier.isAbstract(this.introspectedMethod.getModifiers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return Modifier.isStatic(this.introspectedMethod.getModifiers());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -82,6 +82,11 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
|
|||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbstract() {
|
||||
return ((this.access & Opcodes.ACC_ABSTRACT) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return ((this.access & Opcodes.ACC_STATIC) != 0);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -25,6 +25,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -51,11 +52,18 @@ public abstract class ReflectionUtils {
|
|||
private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$";
|
||||
|
||||
/**
|
||||
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast resolution.
|
||||
* Cache for {@link Class#getDeclaredMethods()} plus equivalent default methods
|
||||
* from Java 8 based interfaces, allowing for fast iteration.
|
||||
*/
|
||||
private static final Map<Class<?>, Method[]> declaredMethodsCache =
|
||||
new ConcurrentReferenceHashMap<Class<?>, Method[]>(256);
|
||||
|
||||
/**
|
||||
* Cache for {@link Class#getDeclaredFields()}, allowing for fast iteration.
|
||||
*/
|
||||
private static final Map<Class<?>, Field[]> declaredFieldsCache =
|
||||
new ConcurrentReferenceHashMap<Class<?>, Field[]>(256);
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to find a {@link Field field} on the supplied {@link Class} with the
|
||||
|
@ -82,7 +90,7 @@ public abstract class ReflectionUtils {
|
|||
Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified");
|
||||
Class<?> searchType = clazz;
|
||||
while (!Object.class.equals(searchType) && searchType != null) {
|
||||
Field[] fields = searchType.getDeclaredFields();
|
||||
Field[] fields = getDeclaredFields(searchType);
|
||||
for (Field field : fields) {
|
||||
if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {
|
||||
return field;
|
||||
|
@ -440,8 +448,8 @@ public abstract class ReflectionUtils {
|
|||
* @see java.lang.reflect.Method#setAccessible
|
||||
*/
|
||||
public static void makeAccessible(Method method) {
|
||||
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) &&
|
||||
!method.isAccessible()) {
|
||||
if ((!Modifier.isPublic(method.getModifiers()) ||
|
||||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
|
||||
method.setAccessible(true);
|
||||
}
|
||||
}
|
||||
|
@ -455,22 +463,43 @@ public abstract class ReflectionUtils {
|
|||
* @see java.lang.reflect.Constructor#setAccessible
|
||||
*/
|
||||
public static void makeAccessible(Constructor<?> ctor) {
|
||||
if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) &&
|
||||
!ctor.isAccessible()) {
|
||||
if ((!Modifier.isPublic(ctor.getModifiers()) ||
|
||||
!Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) {
|
||||
ctor.setAccessible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given callback operation on all matching methods of the given
|
||||
* class, as locally declared or equivalent thereof (such as default methods
|
||||
* on Java 8 based interfaces that the given class implements).
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @since 4.2
|
||||
* @see #doWithMethods
|
||||
*/
|
||||
public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
|
||||
Method[] methods = getDeclaredMethods(clazz);
|
||||
for (Method method : methods) {
|
||||
try {
|
||||
mc.doWith(method);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given callback operation on all matching methods of the given
|
||||
* class and superclasses.
|
||||
* <p>The same named method occurring on subclass and superclass will appear
|
||||
* twice, unless excluded by a {@link MethodFilter}.
|
||||
* @param clazz class to start looking at
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @see #doWithMethods(Class, MethodCallback, MethodFilter)
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException {
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
|
||||
doWithMethods(clazz, mc, null);
|
||||
}
|
||||
|
||||
|
@ -479,13 +508,11 @@ public abstract class ReflectionUtils {
|
|||
* class and superclasses (or given interface and super-interfaces).
|
||||
* <p>The same named method occurring on subclass and superclass will appear
|
||||
* twice, unless excluded by the specified {@link MethodFilter}.
|
||||
* @param clazz class to start looking at
|
||||
* @param clazz the class to introspect
|
||||
* @param mc the callback to invoke for each method
|
||||
* @param mf the filter that determines the methods to apply the callback to
|
||||
*/
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
Method[] methods = getDeclaredMethods(clazz);
|
||||
for (Method method : methods) {
|
||||
|
@ -496,7 +523,7 @@ public abstract class ReflectionUtils {
|
|||
mc.doWith(method);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName() + "': " + ex);
|
||||
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
|
||||
}
|
||||
}
|
||||
if (clazz.getSuperclass() != null) {
|
||||
|
@ -510,10 +537,11 @@ public abstract class ReflectionUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all declared methods on the leaf class and all superclasses. Leaf
|
||||
* class methods are included first.
|
||||
* Get all declared methods on the leaf class and all superclasses.
|
||||
* Leaf class methods are included first.
|
||||
* @param leafClass the class to introspect
|
||||
*/
|
||||
public static Method[] getAllDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {
|
||||
public static Method[] getAllDeclaredMethods(Class<?> leafClass) {
|
||||
final List<Method> methods = new ArrayList<Method>(32);
|
||||
doWithMethods(leafClass, new MethodCallback() {
|
||||
@Override
|
||||
|
@ -525,11 +553,12 @@ public abstract class ReflectionUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the unique set of declared methods on the leaf class and all superclasses. Leaf
|
||||
* class methods are included first and while traversing the superclass hierarchy any methods found
|
||||
* with signatures matching a method already included are filtered out.
|
||||
* Get the unique set of declared methods on the leaf class and all superclasses.
|
||||
* Leaf class methods are included first and while traversing the superclass hierarchy
|
||||
* any methods found with signatures matching a method already included are filtered out.
|
||||
* @param leafClass the class to introspect
|
||||
*/
|
||||
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {
|
||||
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) {
|
||||
final List<Method> methods = new ArrayList<Method>(32);
|
||||
doWithMethods(leafClass, new MethodCallback() {
|
||||
@Override
|
||||
|
@ -562,25 +591,77 @@ public abstract class ReflectionUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method retrieves {@link Class#getDeclaredMethods()} from a local cache
|
||||
* This variant retrieves {@link Class#getDeclaredMethods()} from a local cache
|
||||
* in order to avoid the JVM's SecurityManager check and defensive array copying.
|
||||
* In addition, it also includes Java 8 default methods from locally implemented
|
||||
* interfaces, since those are effectively to be treated just like declared methods.
|
||||
* @param clazz the class to introspect
|
||||
* @return the cached array of methods
|
||||
* @see Class#getDeclaredMethods()
|
||||
*/
|
||||
private static Method[] getDeclaredMethods(Class<?> clazz) {
|
||||
Method[] result = declaredMethodsCache.get(clazz);
|
||||
if (result == null) {
|
||||
result = clazz.getDeclaredMethods();
|
||||
Method[] declaredMethods = clazz.getDeclaredMethods();
|
||||
List<Method> defaultMethods = findConcreteMethodsOnInterfaces(clazz);
|
||||
if (defaultMethods != null) {
|
||||
result = new Method[declaredMethods.length + defaultMethods.size()];
|
||||
System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length);
|
||||
int index = declaredMethods.length;
|
||||
for (Method defaultMethod : defaultMethods) {
|
||||
result[index] = defaultMethod;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = declaredMethods;
|
||||
}
|
||||
declaredMethodsCache.put(clazz, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Method> findConcreteMethodsOnInterfaces(Class<?> clazz) {
|
||||
List<Method> result = null;
|
||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||
for (Method ifcMethod : ifc.getMethods()) {
|
||||
if (!Modifier.isAbstract(ifcMethod.getModifiers())) {
|
||||
if (result == null) {
|
||||
result = new LinkedList<Method>();
|
||||
}
|
||||
result.add(ifcMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given callback on all fields in the target class, going up the
|
||||
* class hierarchy to get all declared fields.
|
||||
* @param clazz the target class to analyze
|
||||
* @param fc the callback to invoke for each field
|
||||
* @since 4.2
|
||||
* @see #doWithFields
|
||||
*/
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc) throws IllegalArgumentException {
|
||||
public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
|
||||
for (Field field : getDeclaredFields(clazz)) {
|
||||
try {
|
||||
fc.doWith(field);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given callback on all fields in the target class, going up the
|
||||
* class hierarchy to get all declared fields.
|
||||
* @param clazz the target class to analyze
|
||||
* @param fc the callback to invoke for each field
|
||||
*/
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc) {
|
||||
doWithFields(clazz, fc, null);
|
||||
}
|
||||
|
||||
|
@ -591,15 +672,12 @@ public abstract class ReflectionUtils {
|
|||
* @param fc the callback to invoke for each field
|
||||
* @param ff the filter that determines the fields to apply the callback to
|
||||
*/
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff) {
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
Class<?> targetClass = clazz;
|
||||
do {
|
||||
Field[] fields = targetClass.getDeclaredFields();
|
||||
Field[] fields = getDeclaredFields(targetClass);
|
||||
for (Field field : fields) {
|
||||
// Skip static and final fields.
|
||||
if (ff != null && !ff.matches(field)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -607,7 +685,7 @@ public abstract class ReflectionUtils {
|
|||
fc.doWith(field);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Shouldn't be illegal to access field '" + field.getName() + "': " + ex);
|
||||
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
|
||||
}
|
||||
}
|
||||
targetClass = targetClass.getSuperclass();
|
||||
|
@ -615,13 +693,28 @@ public abstract class ReflectionUtils {
|
|||
while (targetClass != null && targetClass != Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This variant retrieves {@link Class#getDeclaredFields()} from a local cache
|
||||
* in order to avoid the JVM's SecurityManager check and defensive array copying.
|
||||
* @param clazz the class to introspect
|
||||
* @return the cached array of fields
|
||||
* @see Class#getDeclaredFields()
|
||||
*/
|
||||
private static Field[] getDeclaredFields(Class<?> clazz) {
|
||||
Field[] result = declaredFieldsCache.get(clazz);
|
||||
if (result == null) {
|
||||
result = clazz.getDeclaredFields();
|
||||
declaredFieldsCache.put(clazz, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the source object and the destination, which must be the same class
|
||||
* or a subclass, copy all fields, including inherited fields. Designed to
|
||||
* work on objects with public no-arg constructors.
|
||||
* @throws IllegalArgumentException if the arguments are incompatible
|
||||
*/
|
||||
public static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException {
|
||||
public static void shallowCopyFieldState(final Object src, final Object dest) {
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("Source for field copy cannot be null");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -66,8 +66,8 @@ public class ReflectionUtilsTests {
|
|||
|
||||
@Test
|
||||
public void setField() {
|
||||
final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
|
||||
final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
|
||||
TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
|
||||
Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
|
||||
|
@ -79,13 +79,6 @@ public class ReflectionUtilsTests {
|
|||
assertNull(testBean.getName());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void setFieldIllegal() {
|
||||
final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
|
||||
final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
|
||||
ReflectionUtils.setField(field, testBean, "FooBar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokeMethod() throws Exception {
|
||||
String rob = "Rob Harrop";
|
||||
|
@ -94,65 +87,50 @@ public class ReflectionUtilsTests {
|
|||
bean.setName(rob);
|
||||
|
||||
Method getName = TestObject.class.getMethod("getName", (Class[]) null);
|
||||
Method setName = TestObject.class.getMethod("setName", new Class[] { String.class });
|
||||
Method setName = TestObject.class.getMethod("setName", String.class);
|
||||
|
||||
Object name = ReflectionUtils.invokeMethod(getName, bean);
|
||||
assertEquals("Incorrect name returned", rob, name);
|
||||
|
||||
String juergen = "Juergen Hoeller";
|
||||
ReflectionUtils.invokeMethod(setName, bean, new Object[] { juergen });
|
||||
ReflectionUtils.invokeMethod(setName, bean, juergen);
|
||||
assertEquals("Incorrect name set", juergen, bean.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void declaresException() throws Exception {
|
||||
Method remoteExMethod = A.class.getDeclaredMethod("foo", new Class[] { Integer.class });
|
||||
Method remoteExMethod = A.class.getDeclaredMethod("foo", Integer.class);
|
||||
assertTrue(ReflectionUtils.declaresException(remoteExMethod, RemoteException.class));
|
||||
assertTrue(ReflectionUtils.declaresException(remoteExMethod, ConnectException.class));
|
||||
assertFalse(ReflectionUtils.declaresException(remoteExMethod, NoSuchMethodException.class));
|
||||
assertFalse(ReflectionUtils.declaresException(remoteExMethod, Exception.class));
|
||||
|
||||
Method illegalExMethod = B.class.getDeclaredMethod("bar", new Class[] { String.class });
|
||||
Method illegalExMethod = B.class.getDeclaredMethod("bar", String.class);
|
||||
assertTrue(ReflectionUtils.declaresException(illegalExMethod, IllegalArgumentException.class));
|
||||
assertTrue(ReflectionUtils.declaresException(illegalExMethod, NumberFormatException.class));
|
||||
assertFalse(ReflectionUtils.declaresException(illegalExMethod, IllegalStateException.class));
|
||||
assertFalse(ReflectionUtils.declaresException(illegalExMethod, Exception.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void copySrcToDestinationOfIncorrectClass() {
|
||||
TestObject src = new TestObject();
|
||||
String dest = new String();
|
||||
try {
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Ok
|
||||
}
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullSrc() {
|
||||
TestObject src = null;
|
||||
String dest = new String();
|
||||
try {
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Ok
|
||||
}
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullDest() {
|
||||
TestObject src = new TestObject();
|
||||
String dest = null;
|
||||
try {
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Ok
|
||||
}
|
||||
ReflectionUtils.shallowCopyFieldState(src, dest);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -402,39 +402,49 @@ public class PersistenceAnnotationBeanPostProcessor
|
|||
return metadata;
|
||||
}
|
||||
|
||||
private InjectionMetadata buildPersistenceMetadata(Class<?> clazz) {
|
||||
private InjectionMetadata buildPersistenceMetadata(final Class<?> clazz) {
|
||||
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
Class<?> targetClass = clazz;
|
||||
|
||||
do {
|
||||
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
for (Field field : targetClass.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(PersistenceContext.class) ||
|
||||
field.isAnnotationPresent(PersistenceUnit.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("Persistence annotations are not supported on static fields");
|
||||
final LinkedList<InjectionMetadata.InjectedElement> currElements =
|
||||
new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
|
||||
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
|
||||
if (field.isAnnotationPresent(PersistenceContext.class) ||
|
||||
field.isAnnotationPresent(PersistenceUnit.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("Persistence annotations are not supported on static fields");
|
||||
}
|
||||
currElements.add(new PersistenceElement(field, field, null));
|
||||
}
|
||||
currElements.add(new PersistenceElement(field, field, null));
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
continue;
|
||||
}
|
||||
if ((bridgedMethod.isAnnotationPresent(PersistenceContext.class) ||
|
||||
bridgedMethod.isAnnotationPresent(PersistenceUnit.class)) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("Persistence annotations are not supported on static methods");
|
||||
});
|
||||
|
||||
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
return;
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method);
|
||||
if ((bridgedMethod.isAnnotationPresent(PersistenceContext.class) ||
|
||||
bridgedMethod.isAnnotationPresent(PersistenceUnit.class)) &&
|
||||
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("Persistence annotations are not supported on static methods");
|
||||
}
|
||||
if (method.getParameterTypes().length != 1) {
|
||||
throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method);
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new PersistenceElement(method, bridgedMethod, pd));
|
||||
}
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new PersistenceElement(method, bridgedMethod, pd));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elements.addAll(0, currElements);
|
||||
targetClass = targetClass.getSuperclass();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue