+ Added unit test for BeanMethod
This commit is contained in:
parent
72fae2ea19
commit
2bbc4e48ad
|
@ -101,9 +101,7 @@ final class BeanMethod implements BeanMetadataElement {
|
||||||
public <T extends Annotation> T getRequiredAnnotation(Class<T> annoType) {
|
public <T extends Annotation> T getRequiredAnnotation(Class<T> annoType) {
|
||||||
T anno = getAnnotation(annoType);
|
T anno = getAnnotation(annoType);
|
||||||
|
|
||||||
if (anno == null)
|
Assert.notNull(anno, format("annotation %s not found on %s", annoType.getSimpleName(), this));
|
||||||
throw new IllegalStateException(
|
|
||||||
format("annotation %s not found on %s", annoType.getSimpleName(), this));
|
|
||||||
|
|
||||||
return anno;
|
return anno;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +128,9 @@ final class BeanMethod implements BeanMetadataElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location getLocation() {
|
public Location getLocation() {
|
||||||
|
if (declaringClass == null)
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"declaringClass property is null. Call setDeclaringClass() before calling getLocation()");
|
||||||
return new Location(declaringClass.getLocation().getResource(), getSource());
|
return new Location(declaringClass.getLocation().getResource(), getSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,24 +197,24 @@ final class BeanMethod implements BeanMetadataElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@link Bean} methods must be non-private in order to accommodate CGLIB. */
|
/** {@link Bean} methods must be non-private in order to accommodate CGLIB. */
|
||||||
public class PrivateMethodError extends Problem {
|
class PrivateMethodError extends Problem {
|
||||||
public PrivateMethodError() {
|
PrivateMethodError() {
|
||||||
super(format("method '%s' may not be private", getName()),
|
super(format("Method '%s' may not be private; increase the method's visibility to continue", getName()),
|
||||||
BeanMethod.this.getLocation());
|
BeanMethod.this.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@link Bean} methods must be non-final in order to accommodate CGLIB. */
|
/** {@link Bean} methods must be non-final in order to accommodate CGLIB. */
|
||||||
public class FinalMethodError extends Problem {
|
class FinalMethodError extends Problem {
|
||||||
public FinalMethodError() {
|
FinalMethodError() {
|
||||||
super(format("method '%s' may not be final. remove the final modifier to continue", getName()),
|
super(format("Method '%s' may not be final; remove the final modifier to continue", getName()),
|
||||||
BeanMethod.this.getLocation());
|
BeanMethod.this.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InvalidScopedProxyDeclarationError extends Problem {
|
class InvalidScopedProxyDeclarationError extends Problem {
|
||||||
public InvalidScopedProxyDeclarationError(BeanMethod method) {
|
InvalidScopedProxyDeclarationError(BeanMethod method) {
|
||||||
super(format("method %s contains an invalid annotation declaration: scoped proxies "
|
super(format("Method %s contains an invalid annotation declaration: scoped proxies "
|
||||||
+ "cannot be created for singleton/prototype beans", method.getName()),
|
+ "cannot be created for singleton/prototype beans", method.getName()),
|
||||||
BeanMethod.this.getLocation());
|
BeanMethod.this.getLocation());
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,8 @@ class ModelClass implements BeanMetadataElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Location getLocation() {
|
public Location getLocation() {
|
||||||
|
if(getName() == null)
|
||||||
|
throw new IllegalStateException("'name' property is null. Call setName() before calling getLocation()");
|
||||||
return new Location(new ClassPathResource(convertClassNameToResourcePath(getName())), getSource());
|
return new Location(new ClassPathResource(convertClassNameToResourcePath(getName())), getSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.config.java.support;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.springframework.config.java.StandardScopes.*;
|
||||||
|
import static org.springframework.config.java.support.MutableAnnotationUtils.*;
|
||||||
|
import static org.springframework.context.annotation.ScopedProxyMode.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||||
|
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
|
||||||
|
import org.springframework.beans.factory.parsing.Location;
|
||||||
|
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||||
|
import org.springframework.config.java.Bean;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link BeanMethod}.
|
||||||
|
*
|
||||||
|
* @author Chris Beams
|
||||||
|
*/
|
||||||
|
public class BeanMethodTests {
|
||||||
|
|
||||||
|
private ProblemReporter problemReporter = new FailFastProblemReporter();
|
||||||
|
private String beanName = "foo";
|
||||||
|
private Bean beanAnno = createMutableAnnotation(Bean.class);
|
||||||
|
private ModelClass returnType = new ModelClass("FooType");
|
||||||
|
private ConfigurationClass declaringClass = new ConfigurationClass();
|
||||||
|
{ declaringClass.setName("test.Config"); }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWellFormedMethod() {
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno);
|
||||||
|
|
||||||
|
assertThat(beanMethod.getName(), sameInstance(beanName));
|
||||||
|
assertThat(beanMethod.getModifiers(), equalTo(0));
|
||||||
|
assertThat(beanMethod.getReturnType(), sameInstance(returnType));
|
||||||
|
assertThat(beanMethod.getAnnotation(Bean.class), sameInstance(beanAnno));
|
||||||
|
assertThat(beanMethod.getAnnotation(Override.class), nullValue());
|
||||||
|
assertThat(beanMethod.getRequiredAnnotation(Bean.class), sameInstance(beanAnno));
|
||||||
|
try {
|
||||||
|
beanMethod.getRequiredAnnotation(Override.class);
|
||||||
|
fail("expected IllegalArgumentException ex");
|
||||||
|
} catch (IllegalArgumentException ex) { /* expected */ }
|
||||||
|
|
||||||
|
// must call setDeclaringClass() before calling getLocation()
|
||||||
|
try {
|
||||||
|
beanMethod.getLocation();
|
||||||
|
fail("expected IllegalStateException ex");
|
||||||
|
} catch (IllegalStateException ex) { /* expected */ }
|
||||||
|
|
||||||
|
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
assertThat(beanMethod.getDeclaringClass(), sameInstance(declaringClass));
|
||||||
|
|
||||||
|
beanMethod.setSource(12); // indicating a line number
|
||||||
|
assertEquals(beanMethod.getSource(), 12);
|
||||||
|
|
||||||
|
Location location = beanMethod.getLocation();
|
||||||
|
assertEquals(location.getResource(), new ClassPathResource("test/Config"));
|
||||||
|
assertEquals(location.getSource(), 12);
|
||||||
|
|
||||||
|
// should validate without throwing as this is a well-formed method
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void finalMethodsAreIllegal() {
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, Modifier.FINAL, returnType, beanAnno);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to final bean method");
|
||||||
|
} catch (BeanDefinitionParsingException ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("remove the final modifier"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void privateMethodsAreIllegal() {
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, Modifier.PRIVATE, returnType, beanAnno);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to private bean method");
|
||||||
|
} catch (BeanDefinitionParsingException ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("increase the method's visibility"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void singletonInterfaceScopedProxiesAreIllegal() {
|
||||||
|
Scope scope = SingletonInterfaceProxy.class.getAnnotation(Scope.class);
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to singleton with scoped proxy");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void singletonTargetClassScopedProxiesAreIllegal() {
|
||||||
|
Scope scope = SingletonTargetClassProxy.class.getAnnotation(Scope.class);
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to singleton with scoped proxy");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void singletonsSansProxyAreLegal() {
|
||||||
|
Scope scope = SingletonNoProxy.class.getAnnotation(Scope.class);
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
beanMethod.validate(problemReporter); // should validate without problems - it's legal
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void prototypeInterfaceScopedProxiesAreIllegal() {
|
||||||
|
Scope scope = PrototypeInterfaceProxy.class.getAnnotation(Scope.class);
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to prototype with scoped proxy");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sessionInterfaceScopedProxiesAreLegal() {
|
||||||
|
Scope scope = PrototypeInterfaceProxy.class.getAnnotation(Scope.class);
|
||||||
|
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
|
||||||
|
beanMethod.setDeclaringClass(declaringClass);
|
||||||
|
try {
|
||||||
|
beanMethod.validate(problemReporter);
|
||||||
|
fail("should have failed due to prototype with scoped proxy");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scope(value=SINGLETON, proxyMode=INTERFACES)
|
||||||
|
private class SingletonInterfaceProxy { }
|
||||||
|
|
||||||
|
@Scope(value=SINGLETON, proxyMode=TARGET_CLASS)
|
||||||
|
private class SingletonTargetClassProxy { }
|
||||||
|
|
||||||
|
@Scope(value=SINGLETON, proxyMode=NO)
|
||||||
|
private class SingletonNoProxy { }
|
||||||
|
|
||||||
|
@Scope(value=PROTOTYPE, proxyMode=INTERFACES)
|
||||||
|
private class PrototypeInterfaceProxy { }
|
||||||
|
|
||||||
|
@Scope(value=SESSION, proxyMode=INTERFACES)
|
||||||
|
private class SessionInterfaceProxy { }
|
||||||
|
}
|
Loading…
Reference in New Issue