/*
* Copyright 2012-2016 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.boot.test.autoconfigure.properties;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.annotation.AliasFor;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link AnnotationsPropertySource}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class AnnotationsPropertySourceTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void createWhenSourceIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Property source must not be null");
new AnnotationsPropertySource(null);
}
@Test
public void propertiesWhenHasNoAnnotationShouldBeEmpty() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
NoAnnotation.class);
assertThat(source.getPropertyNames()).isEmpty();
assertThat(source.getProperty("value")).isNull();
}
@Test
public void propertiesWhenHasTypeLevelAnnotationShouldUseAttributeName()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(TypeLevel.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("value")).isEqualTo("abc");
}
@Test
public void propertiesWhenHasTypeLevelWithPrefixShouldUsePrefixedName()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
TypeLevelWithPrefix.class);
assertThat(source.getPropertyNames()).containsExactly("test.value");
assertThat(source.getProperty("test.value")).isEqualTo("abc");
}
@Test
public void propertiesWhenHasAttributeLevelWithPrefixShouldUsePrefixedName()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
AttributeLevelWithPrefix.class);
assertThat(source.getPropertyNames()).containsExactly("test");
assertThat(source.getProperty("test")).isEqualTo("abc");
}
@Test
public void propertiesWhenHasTypeAndAttributeLevelWithPrefixShouldUsePrefixedName()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
TypeAndAttributeLevelWithPrefix.class);
assertThat(source.getPropertyNames()).containsExactly("test.example");
assertThat(source.getProperty("test.example")).isEqualTo("abc");
}
@Test
public void propertiesWhenNotMappedAtTypeLevelShouldIgnoreAttributes()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
NotMappedAtTypeLevel.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("ignore")).isNull();
}
@Test
public void propertiesWhenNotMappedAtAttributeLevelShouldIgnoreAttributes()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
NotMappedAtAttributeLevel.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("ignore")).isNull();
}
@Test
public void propertiesWhenContainsArraysShouldExpandNames() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(Arrays.class);
assertThat(source.getPropertyNames()).contains("strings[0]", "strings[1]",
"classes[0]", "classes[1]", "ints[0]", "ints[1]", "longs[0]", "longs[1]",
"floats[0]", "floats[1]", "doubles[0]", "doubles[1]", "booleans[0]",
"booleans[1]");
assertThat(source.getProperty("strings[0]")).isEqualTo("a");
assertThat(source.getProperty("strings[1]")).isEqualTo("b");
assertThat(source.getProperty("classes[0]")).isEqualTo(Integer.class);
assertThat(source.getProperty("classes[1]")).isEqualTo(Long.class);
assertThat(source.getProperty("ints[0]")).isEqualTo(1);
assertThat(source.getProperty("ints[1]")).isEqualTo(2);
assertThat(source.getProperty("longs[0]")).isEqualTo(1L);
assertThat(source.getProperty("longs[1]")).isEqualTo(2L);
assertThat(source.getProperty("floats[0]")).isEqualTo(1.0f);
assertThat(source.getProperty("floats[1]")).isEqualTo(2.0f);
assertThat(source.getProperty("doubles[0]")).isEqualTo(1.0);
assertThat(source.getProperty("doubles[1]")).isEqualTo(2.0);
assertThat(source.getProperty("booleans[0]")).isEqualTo(false);
assertThat(source.getProperty("booleans[1]")).isEqualTo(true);
}
@Test
public void propertiesWhenHasCamelCaseShouldConvertToKebabCase() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
CamelCaseToKebabCase.class);
assertThat(source.getPropertyNames()).contains("camel-case-to-kebab-case");
}
@Test
public void propertiesFromMetaAnnotationsAreMapped() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertiesFromSingleMetaAnnotation.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("value")).isEqualTo("foo");
}
@Test
public void propertiesFromMultipleMetaAnnotationsAreMappedUsingTheirOwnPropertyMapping()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertiesFromMultipleMetaAnnotations.class);
assertThat(source.getPropertyNames()).containsExactly("value", "test.value",
"test.example");
assertThat(source.getProperty("value")).isEqualTo("alpha");
assertThat(source.getProperty("test.value")).isEqualTo("bravo");
assertThat(source.getProperty("test.example")).isEqualTo("charlie");
}
@Test
public void propertyMappedAttributesCanBeAliased() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertyMappedAttributeWithAnAlias.class);
assertThat(source.getPropertyNames()).containsExactly("aliasing.value");
assertThat(source.getProperty("aliasing.value")).isEqualTo("baz");
}
@Test
public void selfAnnotatingAnnotationDoesNotCauseStackOverflow() {
new AnnotationsPropertySource(PropertyMappedWithSelfAnnotatingAnnotation.class);
}
@Test
public void typeLevelAnnotationOnSuperClass() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertyMappedAnnotationOnSuperClass.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("value")).isEqualTo("abc");
}
@Test
public void aliasedPropertyMappedAttributeOnSuperClass() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
AliasedPropertyMappedAnnotationOnSuperClass.class);
assertThat(source.getPropertyNames()).containsExactly("aliasing.value");
assertThat(source.getProperty("aliasing.value")).isEqualTo("baz");
}
@Test
public void enumValueMapped() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
EnumValueMapped.class);
assertThat(source.getProperty("testenum.value")).isEqualTo(EnumItem.TWO);
}
@Test
public void enumValueNotMapped() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
EnumValueNotMapped.class);
assertThat(source.containsProperty("testenum.value")).isFalse();
}
static class NoAnnotation {
}
@TypeLevelAnnotation("abc")
static class TypeLevel {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping
static @interface TypeLevelAnnotation {
String value();
}
@TypeLevelWithPrefixAnnotation("abc")
static class TypeLevelWithPrefix {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping("test")
static @interface TypeLevelWithPrefixAnnotation {
String value();
}
@AttributeLevelWithPrefixAnnotation("abc")
static class AttributeLevelWithPrefix {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AttributeLevelWithPrefixAnnotation {
@PropertyMapping("test")
String value();
}
@TypeAndAttributeLevelWithPrefixAnnotation("abc")
static class TypeAndAttributeLevelWithPrefix {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping("test")
static @interface TypeAndAttributeLevelWithPrefixAnnotation {
@PropertyMapping("example")
String value();
}
@NotMappedAtTypeLevelAnnotation("abc")
static class NotMappedAtTypeLevel {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping(skip = SkipPropertyMapping.YES)
static @interface NotMappedAtTypeLevelAnnotation {
@PropertyMapping
String value();
String ignore() default "xyz";
}
@NotMappedAtAttributeLevelAnnotation("abc")
static class NotMappedAtAttributeLevel {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping
static @interface NotMappedAtAttributeLevelAnnotation {
String value();
@PropertyMapping(skip = SkipPropertyMapping.YES)
String ignore() default "xyz";
}
@ArraysAnnotation(strings = { "a", "b" }, classes = { Integer.class,
Long.class }, ints = { 1, 2 }, longs = { 1, 2 }, floats = { 1.0f,
2.0f }, doubles = { 1.0, 2.0 }, booleans = { false, true })
static class Arrays {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping
static @interface ArraysAnnotation {
String[] strings();
Class<?>[] classes();
int[] ints();
long[] longs();
float[] floats();
double[] doubles();
boolean[] booleans();
}
@CamelCaseToKebabCaseAnnotation
static class CamelCaseToKebabCase {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping
static @interface CamelCaseToKebabCaseAnnotation {
String camelCaseToKebabCase() default "abc";
}
@PropertiesFromSingleMetaAnnotationAnnotation
static class PropertiesFromSingleMetaAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
@TypeLevelAnnotation("foo")
static @interface PropertiesFromSingleMetaAnnotationAnnotation {
}
@PropertiesFromMultipleMetaAnnotationsAnnotation
static class PropertiesFromMultipleMetaAnnotations {
}
@Retention(RetentionPolicy.RUNTIME)
@TypeLevelAnnotation("alpha")
@TypeLevelWithPrefixAnnotation("bravo")
@TypeAndAttributeLevelWithPrefixAnnotation("charlie")
static @interface PropertiesFromMultipleMetaAnnotationsAnnotation {
}
@AttributeWithAliasAnnotation("baz")
static class PropertyMappedAttributeWithAnAlias {
}
@Retention(RetentionPolicy.RUNTIME)
@AliasedAttributeAnnotation
static @interface AttributeWithAliasAnnotation {
@AliasFor(annotation = AliasedAttributeAnnotation.class, attribute = "value")
String value() default "foo";
String someOtherAttribute() default "shouldNotBeMapped";
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping("aliasing")
static @interface AliasedAttributeAnnotation {
String value() default "bar";
}
@Retention(RetentionPolicy.RUNTIME)
@SelfAnnotating
static @interface SelfAnnotating {
}
@SelfAnnotating
static class PropertyMappedWithSelfAnnotatingAnnotation {
}
static class PropertyMappedAnnotationOnSuperClass extends TypeLevel {
}
static class AliasedPropertyMappedAnnotationOnSuperClass
extends PropertyMappedAttributeWithAnAlias {
}
@EnumAnnotation(EnumItem.TWO)
static class EnumValueMapped {
}
@EnumAnnotation(EnumItem.DEFAULT)
static class EnumValueNotMapped {
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping("testenum")
static @interface EnumAnnotation {
@PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE)
EnumItem value() default EnumItem.DEFAULT;
}
enum EnumItem {
DEFAULT,
ONE,
TWO
}
}