mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
!702 合成注解相关功能重构,添加支持通过@Link及其子注解,实现注解中属性的互为镜像、可选覆盖以及强制覆盖三种模式的别名机制的新特性
Merge pull request !702 from Createsequence/feat-link-annotation-clean
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class AbstractWrappedAnnotationAttributeTest {
|
||||
|
||||
@Test
|
||||
public void workTest() {
|
||||
Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest1.class);
|
||||
Method valueMethod = ReflectUtil.getMethod(AnnotationForTest1.class, "value1");
|
||||
CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
Method nameMethod = ReflectUtil.getMethod(AnnotationForTest1.class, "name1");
|
||||
CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
AbstractWrappedAnnotationAttribute nameWrapper = new TestWrappedAnnotationAttribute(nameAttribute, valueAttribute);
|
||||
|
||||
Assert.assertEquals(nameWrapper.getAnnotation(), annotation);
|
||||
|
||||
// 注解属性
|
||||
Assert.assertEquals(annotation, nameWrapper.getAnnotation());
|
||||
Assert.assertEquals(annotation.annotationType(), nameWrapper.getAnnotationType());
|
||||
Assert.assertEquals(nameAttribute, nameWrapper.getOriginal());
|
||||
Assert.assertEquals(valueAttribute, nameWrapper.getLinked());
|
||||
|
||||
// 方法属性
|
||||
Assert.assertEquals(nameMethod.getName(), nameWrapper.getAttributeName());
|
||||
Assert.assertEquals(nameMethod.getReturnType(), nameWrapper.getAttributeType());
|
||||
Assert.assertTrue(nameWrapper.isWrapped());
|
||||
Assert.assertEquals("value1", nameWrapper.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiWrapperTest() {
|
||||
// 包装第一层: name1 + value1
|
||||
Annotation annotation1 = ClassForTest1.class.getAnnotation(AnnotationForTest1.class);
|
||||
Method value1Method = ReflectUtil.getMethod(AnnotationForTest1.class, "value1");
|
||||
CacheableAnnotationAttribute value1Attribute = new CacheableAnnotationAttribute(annotation1, value1Method);
|
||||
Method name1Method = ReflectUtil.getMethod(AnnotationForTest1.class, "name1");
|
||||
CacheableAnnotationAttribute name1Attribute = new CacheableAnnotationAttribute(annotation1, name1Method);
|
||||
AbstractWrappedAnnotationAttribute wrapper1 = new TestWrappedAnnotationAttribute(name1Attribute, value1Attribute);
|
||||
Assert.assertEquals(name1Attribute, wrapper1.getNonWrappedOriginal());
|
||||
Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute), wrapper1.getAllLinkedNonWrappedAttributes());
|
||||
|
||||
// 包装第二层:( name1 + value1 ) + value2
|
||||
Annotation annotation2 = ClassForTest1.class.getAnnotation(AnnotationForTest2.class);
|
||||
Method value2Method = ReflectUtil.getMethod(AnnotationForTest2.class, "value2");
|
||||
CacheableAnnotationAttribute value2Attribute = new CacheableAnnotationAttribute(annotation2, value2Method);
|
||||
AbstractWrappedAnnotationAttribute wrapper2 = new TestWrappedAnnotationAttribute(wrapper1, value2Attribute);
|
||||
Assert.assertEquals(name1Attribute, wrapper2.getNonWrappedOriginal());
|
||||
Assert.assertEquals(CollUtil.newArrayList(name1Attribute, value1Attribute, value2Attribute), wrapper2.getAllLinkedNonWrappedAttributes());
|
||||
|
||||
// 包装第二层:value3 + ( ( name1 + value1 ) + value2 )
|
||||
Annotation annotation3 = ClassForTest1.class.getAnnotation(AnnotationForTest3.class);
|
||||
Method value3Method = ReflectUtil.getMethod(AnnotationForTest3.class, "value3");
|
||||
CacheableAnnotationAttribute value3Attribute = new CacheableAnnotationAttribute(annotation3, value3Method);
|
||||
AbstractWrappedAnnotationAttribute wrapper3 = new TestWrappedAnnotationAttribute(value3Attribute, wrapper2);
|
||||
Assert.assertEquals(value3Attribute, wrapper3.getNonWrappedOriginal());
|
||||
Assert.assertEquals(CollUtil.newArrayList(value3Attribute, name1Attribute, value1Attribute, value2Attribute), wrapper3.getAllLinkedNonWrappedAttributes());
|
||||
|
||||
}
|
||||
|
||||
static class TestWrappedAnnotationAttribute extends AbstractWrappedAnnotationAttribute {
|
||||
protected TestWrappedAnnotationAttribute(AnnotationAttribute original, AnnotationAttribute linked) {
|
||||
super(original, linked);
|
||||
}
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return linked.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueEquivalentToDefaultValue() {
|
||||
return getOriginal().isValueEquivalentToDefaultValue() && getLinked().isValueEquivalentToDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest1 {
|
||||
String value1() default "";
|
||||
String name1() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest2 {
|
||||
String value2() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest3 {
|
||||
String value3() default "";
|
||||
}
|
||||
|
||||
@AnnotationForTest1(name1 = "name1", value1 = "value1")
|
||||
@AnnotationForTest2(value2 = "value2")
|
||||
@AnnotationForTest3(value3 = "value3")
|
||||
static class ClassForTest1 {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class AliasAnnotationPostProcessorTest {
|
||||
|
||||
@Test
|
||||
public void processTest() {
|
||||
AliasAnnotationPostProcessor processor = new AliasAnnotationPostProcessor();
|
||||
|
||||
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
|
||||
SynthesizedAggregateAnnotation synthesizedAnnotationAggregator = new TestSynthesizedAggregateAnnotation(annotationMap);
|
||||
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
|
||||
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
|
||||
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
|
||||
|
||||
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
|
||||
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
|
||||
Assert.assertTrue(valueAttribute.isWrapped());
|
||||
Assert.assertEquals(ForceAliasedAnnotationAttribute.class, valueAttribute.getClass());
|
||||
|
||||
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
|
||||
Assert.assertFalse(nameAttribute.isWrapped());
|
||||
Assert.assertEquals(CacheableAnnotationAttribute.class, nameAttribute.getClass());
|
||||
|
||||
Assert.assertEquals(nameAttribute, ((WrappedAnnotationAttribute)valueAttribute).getLinked());
|
||||
}
|
||||
|
||||
@AnnotationForTest
|
||||
static class ClassForTest {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
@Alias("name")
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
static class TestSynthesizedAggregateAnnotation implements SynthesizedAggregateAnnotation {
|
||||
|
||||
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
|
||||
|
||||
public TestSynthesizedAggregateAnnotation(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
|
||||
this.annotationMap = annotationMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationSelector getAnnotationSelector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationPostProcessors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
|
||||
return annotationMap.get(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Class<? extends Annotation>, SynthesizedAnnotation> getAllSynthesizedAnnotation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T synthesize(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
|
||||
|
||||
private final Annotation annotation;
|
||||
private final SynthesizedAggregateAnnotation owner;
|
||||
private final Map<String, AnnotationAttribute> attributeMap;
|
||||
|
||||
public TestSynthesizedAnnotation(SynthesizedAggregateAnnotation owner, Annotation annotation) {
|
||||
this.owner = owner;
|
||||
this.attributeMap = new HashMap<>();
|
||||
this.annotation = annotation;
|
||||
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
|
||||
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String attributeName, Class<?> returnType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AnnotationAttribute> getAttributes() {
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
|
||||
attributeMap.put(attributeName, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
|
||||
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
|
||||
if (ObjectUtil.isNotNull(annotationAttribute)) {
|
||||
attributeMap.put(attributeName, operator.apply(annotationAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class AliasLinkAnnotationPostProcessorTest {
|
||||
|
||||
@Test
|
||||
public void processForceAliasForTest() {
|
||||
AliasLinkAnnotationPostProcessor processor = new AliasLinkAnnotationPostProcessor();
|
||||
|
||||
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
|
||||
SynthesizedAggregateAnnotation synthesizedAnnotationAggregator = new TestSynthesizedAggregateAnnotation(annotationMap);
|
||||
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
|
||||
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
|
||||
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
|
||||
|
||||
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
|
||||
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
|
||||
Assert.assertFalse(valueAttribute.isWrapped());
|
||||
Assert.assertEquals(CacheableAnnotationAttribute.class, valueAttribute.getClass());
|
||||
|
||||
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
|
||||
Assert.assertTrue(nameAttribute.isWrapped());
|
||||
Assert.assertEquals(ForceAliasedAnnotationAttribute.class, nameAttribute.getClass());
|
||||
|
||||
Assert.assertEquals(valueAttribute, ((WrappedAnnotationAttribute)nameAttribute).getLinked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processAliasForTest() {
|
||||
AliasLinkAnnotationPostProcessor processor = new AliasLinkAnnotationPostProcessor();
|
||||
|
||||
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
|
||||
SynthesizedAggregateAnnotation synthesizedAnnotationAggregator = new TestSynthesizedAggregateAnnotation(annotationMap);
|
||||
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
|
||||
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
|
||||
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
|
||||
|
||||
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
|
||||
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value2");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value2"), valueAttribute.getAttribute());
|
||||
Assert.assertFalse(valueAttribute.isWrapped());
|
||||
Assert.assertEquals(CacheableAnnotationAttribute.class, valueAttribute.getClass());
|
||||
|
||||
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name2");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name2"), nameAttribute.getAttribute());
|
||||
Assert.assertTrue(nameAttribute.isWrapped());
|
||||
Assert.assertEquals(AliasedAnnotationAttribute.class, nameAttribute.getClass());
|
||||
|
||||
Assert.assertEquals(valueAttribute, ((WrappedAnnotationAttribute)nameAttribute).getLinked());
|
||||
}
|
||||
|
||||
@AnnotationForTest
|
||||
static class ClassForTest {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
@Link(attribute = "name", type = RelationType.FORCE_ALIAS_FOR)
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
|
||||
@Link(attribute = "name2", type = RelationType.ALIAS_FOR)
|
||||
String value2() default "";
|
||||
String name2() default "";
|
||||
}
|
||||
|
||||
static class TestSynthesizedAggregateAnnotation implements SynthesizedAggregateAnnotation {
|
||||
|
||||
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
|
||||
|
||||
public TestSynthesizedAggregateAnnotation(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
|
||||
this.annotationMap = annotationMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationSelector getAnnotationSelector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationPostProcessors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
|
||||
return annotationMap.get(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Class<? extends Annotation>, SynthesizedAnnotation> getAllSynthesizedAnnotation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T synthesize(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
|
||||
|
||||
private final Annotation annotation;
|
||||
private final SynthesizedAggregateAnnotation owner;
|
||||
private final Map<String, AnnotationAttribute> attributeMap;
|
||||
|
||||
public TestSynthesizedAnnotation(SynthesizedAggregateAnnotation owner, Annotation annotation) {
|
||||
this.owner = owner;
|
||||
this.attributeMap = new HashMap<>();
|
||||
this.annotation = annotation;
|
||||
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
|
||||
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String attributeName, Class<?> returnType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AnnotationAttribute> getAttributes() {
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
|
||||
attributeMap.put(attributeName, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
|
||||
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
|
||||
if (ObjectUtil.isNotNull(annotationAttribute)) {
|
||||
attributeMap.put(attributeName, operator.apply(annotationAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class AliasedAnnotationAttributeTest {
|
||||
|
||||
@Test
|
||||
public void baseInfoTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final AliasedAnnotationAttribute valueAnnotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 注解属性
|
||||
Assert.assertEquals(annotation, valueAnnotationAttribute.getAnnotation());
|
||||
Assert.assertEquals(annotation.annotationType(), valueAnnotationAttribute.getAnnotationType());
|
||||
|
||||
// 方法属性
|
||||
Assert.assertEquals(valueMethod.getAnnotation(Alias.class), valueAnnotationAttribute.getAnnotation(Alias.class));
|
||||
Assert.assertEquals(valueMethod.getName(), valueAnnotationAttribute.getAttributeName());
|
||||
Assert.assertEquals(nameMethod.getReturnType(), valueAnnotationAttribute.getAttributeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final AliasedAnnotationAttribute annotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("name", annotationAttribute.getValue());
|
||||
Assert.assertFalse(annotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(annotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueNonDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest2.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final AliasedAnnotationAttribute annotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("value", annotationAttribute.getValue());
|
||||
Assert.assertFalse(annotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(annotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
@Alias("value")
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@AnnotationForTest(name = "name", value = "value")
|
||||
static class ClassForTest1 {}
|
||||
|
||||
@AnnotationForTest(value = "value")
|
||||
static class ClassForTest2 {}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,7 @@ public class AnnotationUtilTest {
|
||||
// 加别名适配
|
||||
final AnnotationForTest annotation = AnnotationUtil.getAnnotationAlias(ClassWithAnnotation.class, AnnotationForTest.class);
|
||||
Assert.assertEquals("测试", annotation.retry());
|
||||
Assert.assertTrue(AnnotationUtil.isSynthesizedAnnotation(annotation));
|
||||
}
|
||||
|
||||
@AnnotationForTest("测试")
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class CacheableAnnotationAttributeTest {
|
||||
|
||||
@Test
|
||||
public void baseInfoTest() {
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method attribute = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute annotationAttribute = new CacheableAnnotationAttribute(annotation, attribute);
|
||||
// 注解属性
|
||||
Assert.assertEquals(annotation, annotationAttribute.getAnnotation());
|
||||
Assert.assertEquals(annotation.annotationType(), annotationAttribute.getAnnotationType());
|
||||
// 方法属性
|
||||
Assert.assertEquals(attribute.getName(), annotationAttribute.getAttributeName());
|
||||
Assert.assertEquals(attribute.getReturnType(), annotationAttribute.getAttributeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueDefaultTest() {
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method attribute = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute annotationAttribute = new CacheableAnnotationAttribute(annotation, attribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("", annotationAttribute.getValue());
|
||||
Assert.assertTrue(annotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertFalse(annotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueNonDefaultTest() {
|
||||
final Annotation annotation = ClassForTest2.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method attribute = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute annotationAttribute = new CacheableAnnotationAttribute(annotation, attribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("test", annotationAttribute.getValue());
|
||||
Assert.assertFalse(annotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertFalse(annotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@AnnotationForTest("")
|
||||
static class ClassForTest1 {}
|
||||
|
||||
@AnnotationForTest("test")
|
||||
static class ClassForTest2 {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.map.MapBuilder;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class CacheableSynthesizedAnnotationAttributeProcessorTest {
|
||||
|
||||
@Test
|
||||
public void getAttributeValueTest() {
|
||||
CacheableSynthesizedAnnotationAttributeProcessor processor = new CacheableSynthesizedAnnotationAttributeProcessor();
|
||||
|
||||
Map<String, Object> values1 = MapBuilder.<String, Object> create().put("name", "name1").put("value", 111).build();
|
||||
SynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(1, 0, values1);
|
||||
Map<String, Object> values2 = MapBuilder.<String, Object> create().put("name", "name2").put("value", "value2").build();
|
||||
SynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0, values2);
|
||||
|
||||
Assert.assertEquals("name2", processor.getAttributeValue("name", String.class, Arrays.asList(annotation1, annotation2)));
|
||||
Assert.assertEquals(Integer.valueOf(111), processor.getAttributeValue("value", Integer.class, Arrays.asList(annotation1, annotation2)));
|
||||
}
|
||||
|
||||
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
|
||||
|
||||
private final int verticalDistance;
|
||||
private final int horizontalDistance;
|
||||
private final Map<String, Object> value;
|
||||
|
||||
public TestSynthesizedAnnotation(int verticalDistance, int horizontalDistance, Map<String, Object> value) {
|
||||
this.verticalDistance = verticalDistance;
|
||||
this.horizontalDistance = horizontalDistance;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalDistance() {
|
||||
return verticalDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalDistance() {
|
||||
return horizontalDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String attributeName, Class<?> returnType) {
|
||||
return Opt.ofNullable(value.get(attributeName))
|
||||
.map(t -> ClassUtil.isAssignable(returnType, t.getClass()))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AnnotationAttribute> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName) {
|
||||
return value.get(attributeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ForceAliasedAnnotationAttributeTest {
|
||||
|
||||
@Test
|
||||
public void baseInfoTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final ForceAliasedAnnotationAttribute valueAnnotationAttribute = new ForceAliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 注解属性
|
||||
Assert.assertEquals(annotation, valueAnnotationAttribute.getAnnotation());
|
||||
Assert.assertEquals(annotation.annotationType(), valueAnnotationAttribute.getAnnotationType());
|
||||
|
||||
// 方法属性
|
||||
Assert.assertEquals(valueMethod.getName(), valueAnnotationAttribute.getAttributeName());
|
||||
Assert.assertEquals(valueMethod.getReturnType(), valueAnnotationAttribute.getAttributeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final AliasedAnnotationAttribute valueAnnotationAttribute = new AliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("name", valueAnnotationAttribute.getValue());
|
||||
Assert.assertFalse(valueAnnotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(valueAnnotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueNonDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest2.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final ForceAliasedAnnotationAttribute valueAnnotationAttribute = new ForceAliasedAnnotationAttribute(valueAttribute, nameAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("", valueAnnotationAttribute.getValue());
|
||||
Assert.assertTrue(valueAnnotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(valueAnnotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@AnnotationForTest(name = "name", value = "value")
|
||||
static class ClassForTest1 {}
|
||||
|
||||
@AnnotationForTest(value = "value")
|
||||
static class ClassForTest2 {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 合成注解{@link GenericSynthesizedAggregateAnnotation}的测试用例
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public class GenericSynthesizedAggregateAnnotationTest {
|
||||
|
||||
@Test
|
||||
public void baseSynthesisAnnotationWorkTest() {
|
||||
// AnnotatedClass -> @ChildAnnotation -> @ParentAnnotation -> @GrandParentAnnotation
|
||||
// -> @GrandParentAnnotation
|
||||
final GrandParentAnnotation grandParentAnnotation = ChildAnnotation.class.getAnnotation(GrandParentAnnotation.class);
|
||||
final ParentAnnotation parentAnnotation = ChildAnnotation.class.getAnnotation(ParentAnnotation.class);
|
||||
final ChildAnnotation childAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
|
||||
final GenericSynthesizedAggregateAnnotation syntheticMetaAnnotation = new GenericSynthesizedAggregateAnnotation(childAnnotation);
|
||||
|
||||
// Annotation & AnnotatedElement
|
||||
Assert.assertEquals(GenericSynthesizedAggregateAnnotation.class, syntheticMetaAnnotation.annotationType());
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
|
||||
Assert.assertEquals(grandParentAnnotation, syntheticMetaAnnotation.getAnnotation(GrandParentAnnotation.class));
|
||||
Assert.assertEquals(parentAnnotation, syntheticMetaAnnotation.getAnnotation(ParentAnnotation.class));
|
||||
Assert.assertEquals(childAnnotation, syntheticMetaAnnotation.getAnnotation(ChildAnnotation.class));
|
||||
Assert.assertEquals(
|
||||
Arrays.asList(childAnnotation, grandParentAnnotation, parentAnnotation),
|
||||
Arrays.asList(syntheticMetaAnnotation.getAnnotations())
|
||||
);
|
||||
|
||||
// 扩展方法
|
||||
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(GrandParentAnnotation.class));
|
||||
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ParentAnnotation.class));
|
||||
Assert.assertNotNull(syntheticMetaAnnotation.getSynthesizedAnnotation(ChildAnnotation.class));
|
||||
Assert.assertEquals(3, syntheticMetaAnnotation.getAllSynthesizedAnnotation().size());
|
||||
|
||||
// 属性
|
||||
Assert.assertEquals(SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY, syntheticMetaAnnotation.getAnnotationSelector());
|
||||
Assert.assertEquals(CacheableSynthesizedAnnotationAttributeProcessor.class, syntheticMetaAnnotation.getAnnotationAttributeProcessor().getClass());
|
||||
Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotationPostProcessors().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesisAnnotationAttributeTest() {
|
||||
final ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
|
||||
GenericSynthesizedAggregateAnnotation syntheticMetaAnnotation = new GenericSynthesizedAggregateAnnotation(rootAnnotation);
|
||||
Assert.assertEquals(syntheticMetaAnnotation.getSource(), Collections.singletonList(rootAnnotation));
|
||||
Assert.assertEquals(syntheticMetaAnnotation.annotationType(), GenericSynthesizedAggregateAnnotation.class);
|
||||
Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotations().length);
|
||||
|
||||
Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttributeValue("childValue", String.class));
|
||||
Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttributeValue("childValueAlias", String.class));
|
||||
Assert.assertEquals("Child's Parent!", syntheticMetaAnnotation.getAttributeValue("parentValue", String.class));
|
||||
Assert.assertEquals("Child's GrandParent!", syntheticMetaAnnotation.getAttributeValue("grandParentValue", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syntheticAnnotationTest() {
|
||||
final ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
|
||||
GenericSynthesizedAggregateAnnotation syntheticMetaAnnotation = new GenericSynthesizedAggregateAnnotation(rootAnnotation);
|
||||
|
||||
final ChildAnnotation childAnnotation = syntheticMetaAnnotation.synthesize(ChildAnnotation.class);
|
||||
SynthesizedAnnotation childSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(ChildAnnotation.class);
|
||||
Assert.assertNotNull(childSyntheticAnnotation);
|
||||
Assert.assertTrue(childSyntheticAnnotation.hasAttribute("childValue", String.class));
|
||||
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), childSyntheticAnnotation.getRoot());
|
||||
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), childSyntheticAnnotation.getAnnotation());
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
|
||||
Assert.assertNotNull(childAnnotation);
|
||||
Assert.assertEquals("Child!", childAnnotation.childValue());
|
||||
Assert.assertEquals("Child!", childAnnotation.childValueAlias());
|
||||
Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new GenericSynthesizedAggregateAnnotation(childAnnotation));
|
||||
|
||||
final ParentAnnotation parentAnnotation = syntheticMetaAnnotation.synthesize(ParentAnnotation.class);
|
||||
SynthesizedAnnotation parentSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(ParentAnnotation.class);
|
||||
Assert.assertNotNull(parentSyntheticAnnotation);
|
||||
Assert.assertTrue(parentSyntheticAnnotation.hasAttribute("parentValue", String.class));
|
||||
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), parentSyntheticAnnotation.getRoot());
|
||||
Assert.assertEquals(ChildAnnotation.class.getAnnotation(ParentAnnotation.class), parentSyntheticAnnotation.getAnnotation());
|
||||
Assert.assertNotNull(parentAnnotation);
|
||||
Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
|
||||
Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new GenericSynthesizedAggregateAnnotation(parentAnnotation));
|
||||
|
||||
final GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.synthesize(GrandParentAnnotation.class);
|
||||
SynthesizedAnnotation grandParentSyntheticAnnotation = syntheticMetaAnnotation.getSynthesizedAnnotation(GrandParentAnnotation.class);
|
||||
Assert.assertNotNull(grandParentSyntheticAnnotation);
|
||||
Assert.assertTrue(grandParentSyntheticAnnotation.hasAttribute("grandParentType", Class.class));
|
||||
Assert.assertEquals(AnnotatedClass.class.getAnnotation(ChildAnnotation.class), grandParentSyntheticAnnotation.getRoot());
|
||||
Assert.assertEquals(ChildAnnotation.class.getAnnotation(GrandParentAnnotation.class), grandParentSyntheticAnnotation.getAnnotation());
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
|
||||
Assert.assertNotNull(grandParentAnnotation);
|
||||
Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
|
||||
Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new GenericSynthesizedAggregateAnnotation(grandParentAnnotation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkTest() {
|
||||
final Method method = ReflectUtil.getMethod(AnnotationForLinkTest.class, "value");
|
||||
final SynthesizedAggregateAnnotation synthesizedAnnotationAggregator = new GenericSynthesizedAggregateAnnotation(method.getAnnotation(AliasFor.class));
|
||||
final Link link = synthesizedAnnotationAggregator.synthesize(Link.class);
|
||||
Assert.assertEquals(AnnotationForLinkTest.class, link.annotation());
|
||||
Assert.assertEquals("name", link.attribute());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mirrorAttributeTest() {
|
||||
AnnotationForMirrorTest annotation = ClassForMirrorTest.class.getAnnotation(AnnotationForMirrorTest.class);
|
||||
SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
AnnotationForMirrorTest syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
|
||||
Assert.assertEquals("Foo", syntheticAnnotation.name());
|
||||
Assert.assertEquals("Foo", syntheticAnnotation.value());
|
||||
|
||||
annotation = ClassForMirrorTest2.class.getAnnotation(AnnotationForMirrorTest.class);
|
||||
synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
|
||||
Assert.assertEquals("Foo", syntheticAnnotation.name());
|
||||
Assert.assertEquals("Foo", syntheticAnnotation.value());
|
||||
|
||||
annotation = ClassForMirrorTest3.class.getAnnotation(AnnotationForMirrorTest.class);
|
||||
synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
syntheticAnnotation = synthetic.synthesize(AnnotationForMirrorTest.class);
|
||||
AnnotationForMirrorTest finalSyntheticAnnotation = syntheticAnnotation;
|
||||
Assert.assertThrows(IllegalArgumentException.class, finalSyntheticAnnotation::name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliasForTest() {
|
||||
AnnotationForAliasForTest annotation = ClassForAliasForTest.class.getAnnotation(AnnotationForAliasForTest.class);
|
||||
SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
MetaAnnotationForAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForAliasForTest.class);
|
||||
Assert.assertEquals("Meta", metaAnnotation.name());
|
||||
AnnotationForAliasForTest childAnnotation = synthetic.synthesize(AnnotationForAliasForTest.class);
|
||||
Assert.assertEquals("", childAnnotation.value());
|
||||
|
||||
annotation = ClassForAliasForTest2.class.getAnnotation(AnnotationForAliasForTest.class);
|
||||
synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
metaAnnotation = synthetic.synthesize(MetaAnnotationForAliasForTest.class);
|
||||
Assert.assertEquals("Foo", metaAnnotation.name());
|
||||
childAnnotation = synthetic.synthesize(AnnotationForAliasForTest.class);
|
||||
Assert.assertEquals("Foo", childAnnotation.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceAliasForTest() {
|
||||
AnnotationForceForAliasForTest annotation = ClassForForceAliasForTest.class.getAnnotation(AnnotationForceForAliasForTest.class);
|
||||
SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
MetaAnnotationForForceAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForForceAliasForTest.class);
|
||||
Assert.assertEquals("", metaAnnotation.name());
|
||||
AnnotationForceForAliasForTest childAnnotation = synthetic.synthesize(AnnotationForceForAliasForTest.class);
|
||||
Assert.assertEquals("", childAnnotation.value());
|
||||
|
||||
annotation = ClassForForceAliasForTest2.class.getAnnotation(AnnotationForceForAliasForTest.class);
|
||||
synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
metaAnnotation = synthetic.synthesize(MetaAnnotationForForceAliasForTest.class);
|
||||
Assert.assertEquals("Foo", metaAnnotation.name());
|
||||
childAnnotation = synthetic.synthesize(AnnotationForceForAliasForTest.class);
|
||||
Assert.assertEquals("Foo", childAnnotation.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliasForAndMirrorTest() {
|
||||
AnnotationForMirrorThenAliasForTest annotation = ClassForAliasForAndMirrorTest.class.getAnnotation(AnnotationForMirrorThenAliasForTest.class);
|
||||
SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
MetaAnnotationForMirrorThenAliasForTest metaAnnotation = synthetic.synthesize(MetaAnnotationForMirrorThenAliasForTest.class);
|
||||
Assert.assertEquals("test", metaAnnotation.name());
|
||||
Assert.assertEquals("test", metaAnnotation.value());
|
||||
AnnotationForMirrorThenAliasForTest childAnnotation = synthetic.synthesize(AnnotationForMirrorThenAliasForTest.class);
|
||||
Assert.assertEquals("test", childAnnotation.childValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiAliasForTest() {
|
||||
final AnnotationForMultiAliasForTest annotation = ClassForMultiAliasForTest.class.getAnnotation(AnnotationForMultiAliasForTest.class);
|
||||
final SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
|
||||
final MetaAnnotationForMultiAliasForTest1 metaAnnotation1 = synthetic.synthesize(MetaAnnotationForMultiAliasForTest1.class);
|
||||
Assert.assertEquals("test", metaAnnotation1.name());
|
||||
Assert.assertEquals("test", metaAnnotation1.value1());
|
||||
final MetaAnnotationForMultiAliasForTest2 metaAnnotation2 = synthetic.synthesize(MetaAnnotationForMultiAliasForTest2.class);
|
||||
Assert.assertEquals("test", metaAnnotation2.value2());
|
||||
final AnnotationForMultiAliasForTest childAnnotation = synthetic.synthesize(AnnotationForMultiAliasForTest.class);
|
||||
Assert.assertEquals("test", childAnnotation.value3());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void implicitAliasTest() {
|
||||
final AnnotationForImplicitAliasTest annotation = ClassForImplicitAliasTest.class.getAnnotation(AnnotationForImplicitAliasTest.class);
|
||||
final SynthesizedAggregateAnnotation synthetic = new GenericSynthesizedAggregateAnnotation(annotation);
|
||||
|
||||
final MetaAnnotationForImplicitAliasTest metaAnnotation = synthetic.synthesize(MetaAnnotationForImplicitAliasTest.class);
|
||||
Assert.assertEquals("Meta", metaAnnotation.name());
|
||||
Assert.assertEquals("Foo", metaAnnotation.value());
|
||||
final AnnotationForImplicitAliasTest childAnnotation = synthetic.synthesize(AnnotationForImplicitAliasTest.class);
|
||||
Assert.assertEquals("Foo", childAnnotation.value());
|
||||
}
|
||||
|
||||
// 注解结构如下:
|
||||
// AnnotatedClass -> @ChildAnnotation -> @ParentAnnotation -> @GrandParentAnnotation
|
||||
// -> @GrandParentAnnotation
|
||||
@ChildAnnotation(childValueAlias = "Child!", grandParentType = Integer.class)
|
||||
static class AnnotatedClass {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.ANNOTATION_TYPE })
|
||||
@interface GrandParentAnnotation {
|
||||
String grandParentValue() default "";
|
||||
Class<?> grandParentType() default Void.class;
|
||||
}
|
||||
|
||||
@GrandParentAnnotation(grandParentValue = "Parent's GrandParent!") // 覆盖元注解@GrandParentAnnotation的属性
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
@interface ParentAnnotation {
|
||||
String parentValue() default "";
|
||||
String grandParentType() default "java.lang.Void";
|
||||
}
|
||||
|
||||
@GrandParentAnnotation(grandParentValue = "Child's GrandParent!") // 重复的元注解,靠近根注解的优先级高
|
||||
@ParentAnnotation(parentValue = "Child's Parent!") // 覆盖元注解@ParentAnnotation的属性
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface ChildAnnotation {
|
||||
String childValueAlias() default "";
|
||||
@Alias("childValueAlias")
|
||||
String childValue() default "";
|
||||
Class<?> grandParentType() default Void.class;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForMirrorTest {
|
||||
//@Link(attribute = "name")
|
||||
@MirrorFor(attribute = "name")
|
||||
String value() default "";
|
||||
//@Link(attribute = "value")
|
||||
@MirrorFor(attribute = "value")
|
||||
String name() default "";
|
||||
}
|
||||
@AnnotationForMirrorTest("Foo")
|
||||
static class ClassForMirrorTest {}
|
||||
@AnnotationForMirrorTest(name = "Foo")
|
||||
static class ClassForMirrorTest2 {}
|
||||
@AnnotationForMirrorTest(value = "Aoo", name = "Foo")
|
||||
static class ClassForMirrorTest3 {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForAliasForTest {
|
||||
String name() default "";
|
||||
}
|
||||
@MetaAnnotationForAliasForTest(name = "Meta")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForAliasForTest {
|
||||
@AliasFor(
|
||||
annotation = MetaAnnotationForAliasForTest.class,
|
||||
attribute = "name"
|
||||
)
|
||||
String value() default "";
|
||||
}
|
||||
@AnnotationForAliasForTest
|
||||
static class ClassForAliasForTest {}
|
||||
@AnnotationForAliasForTest("Foo")
|
||||
static class ClassForAliasForTest2 {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForForceAliasForTest {
|
||||
String name() default "";
|
||||
}
|
||||
@MetaAnnotationForForceAliasForTest(name = "Meta")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForceForAliasForTest {
|
||||
//@Link(
|
||||
// annotation = MetaAnnotationForForceAliasForTest.class,
|
||||
// attribute = "name",
|
||||
// type = RelationType.FORCE_ALIAS_FOR
|
||||
//)
|
||||
@ForceAliasFor(annotation = MetaAnnotationForForceAliasForTest.class, attribute = "name")
|
||||
String value() default "";
|
||||
}
|
||||
@AnnotationForceForAliasForTest
|
||||
static class ClassForForceAliasForTest {}
|
||||
@AnnotationForceForAliasForTest("Foo")
|
||||
static class ClassForForceAliasForTest2 {}
|
||||
|
||||
@interface AnnotationForLinkTest {
|
||||
@AliasFor(attribute = "name", annotation = AnnotationForLinkTest.class)
|
||||
String value() default "value";
|
||||
String name() default "name";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForMirrorThenAliasForTest {
|
||||
@MirrorFor(attribute = "value")
|
||||
String name() default "";
|
||||
@MirrorFor(attribute = "name")
|
||||
String value() default "";
|
||||
}
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@MetaAnnotationForMirrorThenAliasForTest("Meta")
|
||||
@interface AnnotationForMirrorThenAliasForTest {
|
||||
@AliasFor(attribute = "name", annotation = MetaAnnotationForMirrorThenAliasForTest.class)
|
||||
String childValue() default "value";
|
||||
}
|
||||
@AnnotationForMirrorThenAliasForTest(childValue = "test")
|
||||
static class ClassForAliasForAndMirrorTest{}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForMultiAliasForTest1 {
|
||||
@MirrorFor(attribute = "value1")
|
||||
String name() default "";
|
||||
@MirrorFor(attribute = "name")
|
||||
String value1() default "";
|
||||
}
|
||||
@MetaAnnotationForMultiAliasForTest1
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForMultiAliasForTest2 {
|
||||
@AliasFor(attribute = "name", annotation = MetaAnnotationForMultiAliasForTest1.class)
|
||||
String value2() default "";
|
||||
}
|
||||
@MetaAnnotationForMultiAliasForTest2
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForMultiAliasForTest {
|
||||
@AliasFor(attribute = "value2", annotation = MetaAnnotationForMultiAliasForTest2.class)
|
||||
String value3() default "value";
|
||||
}
|
||||
@AnnotationForMultiAliasForTest(value3 = "test")
|
||||
static class ClassForMultiAliasForTest{}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface MetaAnnotationForImplicitAliasTest {
|
||||
@MirrorFor(attribute = "value")
|
||||
String name() default "";
|
||||
@MirrorFor(attribute = "name")
|
||||
String value() default "";
|
||||
}
|
||||
@MetaAnnotationForImplicitAliasTest("Meta")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForImplicitAliasTest {
|
||||
String value() default "";
|
||||
}
|
||||
@AnnotationForImplicitAliasTest("Foo")
|
||||
static class ClassForImplicitAliasTest {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class MirrorLinkAnnotationPostProcessorTest {
|
||||
|
||||
@Test
|
||||
public void processTest() {
|
||||
MirrorLinkAnnotationPostProcessor processor = new MirrorLinkAnnotationPostProcessor();
|
||||
|
||||
Map<Class<?>, SynthesizedAnnotation> annotationMap = new HashMap<>();
|
||||
SynthesizedAggregateAnnotation synthesizedAnnotationAggregator = new TestSynthesizedAggregateAnnotation(annotationMap);
|
||||
AnnotationForTest annotation = ClassForTest.class.getAnnotation(AnnotationForTest.class);
|
||||
SynthesizedAnnotation synthesizedAnnotation = new TestSynthesizedAnnotation(synthesizedAnnotationAggregator, annotation);
|
||||
annotationMap.put(annotation.annotationType(), synthesizedAnnotation);
|
||||
|
||||
processor.process(synthesizedAnnotation, synthesizedAnnotationAggregator);
|
||||
AnnotationAttribute valueAttribute = synthesizedAnnotation.getAttributes().get("value");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "value"), valueAttribute.getAttribute());
|
||||
Assert.assertTrue(valueAttribute.isWrapped());
|
||||
Assert.assertEquals(MirroredAnnotationAttribute.class, valueAttribute.getClass());
|
||||
|
||||
AnnotationAttribute nameAttribute = synthesizedAnnotation.getAttributes().get("name");
|
||||
Assert.assertEquals(ReflectUtil.getMethod(AnnotationForTest.class, "name"), nameAttribute.getAttribute());
|
||||
Assert.assertTrue(nameAttribute.isWrapped());
|
||||
Assert.assertEquals(MirroredAnnotationAttribute.class, nameAttribute.getClass());
|
||||
|
||||
Assert.assertEquals(((WrappedAnnotationAttribute)nameAttribute).getLinked(), ((WrappedAnnotationAttribute)valueAttribute).getOriginal());
|
||||
Assert.assertEquals(((WrappedAnnotationAttribute)nameAttribute).getOriginal(), ((WrappedAnnotationAttribute)valueAttribute).getLinked());
|
||||
}
|
||||
|
||||
@AnnotationForTest
|
||||
static class ClassForTest {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
@Link(attribute = "name", type = RelationType.MIRROR_FOR)
|
||||
String value() default "";
|
||||
@Link(attribute = "value", type = RelationType.MIRROR_FOR)
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
static class TestSynthesizedAggregateAnnotation implements SynthesizedAggregateAnnotation {
|
||||
|
||||
private final Map<Class<?>, SynthesizedAnnotation> annotationMap;
|
||||
|
||||
public TestSynthesizedAggregateAnnotation(Map<Class<?>, SynthesizedAnnotation> annotationMap) {
|
||||
this.annotationMap = annotationMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationSelector getAnnotationSelector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotationAttributeProcessor getAnnotationAttributeProcessor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SynthesizedAnnotationPostProcessor> getAnnotationPostProcessors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynthesizedAnnotation getSynthesizedAnnotation(Class<?> annotationType) {
|
||||
return annotationMap.get(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Class<? extends Annotation>, SynthesizedAnnotation> getAllSynthesizedAnnotation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T synthesize(Class<T> annotationType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
|
||||
|
||||
private final Annotation annotation;
|
||||
private final SynthesizedAggregateAnnotation owner;
|
||||
private final Map<String, AnnotationAttribute> attributeMap;
|
||||
|
||||
public TestSynthesizedAnnotation(SynthesizedAggregateAnnotation owner, Annotation annotation) {
|
||||
this.owner = owner;
|
||||
this.attributeMap = new HashMap<>();
|
||||
this.annotation = annotation;
|
||||
for (Method declaredMethod : annotation.annotationType().getDeclaredMethods()) {
|
||||
attributeMap.put(declaredMethod.getName(), new CacheableAnnotationAttribute(annotation, declaredMethod));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String attributeName, Class<?> returnType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AnnotationAttribute> getAttributes() {
|
||||
return attributeMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
|
||||
attributeMap.put(attributeName, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
|
||||
AnnotationAttribute annotationAttribute = attributeMap.get(attributeName);
|
||||
if (ObjectUtil.isNotNull(annotationAttribute)) {
|
||||
attributeMap.put(attributeName, operator.apply(annotationAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class MirroredAnnotationAttributeTest {
|
||||
|
||||
@Test
|
||||
public void baseInfoTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final MirroredAnnotationAttribute nameAnnotationAttribute = new MirroredAnnotationAttribute(nameAttribute, valueAttribute);
|
||||
|
||||
// 注解属性
|
||||
Assert.assertEquals(annotation, nameAnnotationAttribute.getAnnotation());
|
||||
Assert.assertEquals(annotation.annotationType(), nameAnnotationAttribute.getAnnotationType());
|
||||
|
||||
// 方法属性
|
||||
Assert.assertEquals(nameMethod.getName(), nameAnnotationAttribute.getAttributeName());
|
||||
Assert.assertEquals(nameMethod.getReturnType(), nameAnnotationAttribute.getAttributeType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest2.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final MirroredAnnotationAttribute nameAnnotationAttribute = new MirroredAnnotationAttribute(nameAttribute, valueAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("", nameAnnotationAttribute.getValue());
|
||||
Assert.assertTrue(nameAnnotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(nameAnnotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workWhenValueNonDefaultTest() {
|
||||
// 组合属性
|
||||
final Annotation annotation = ClassForTest1.class.getAnnotation(AnnotationForTest.class);
|
||||
final Method valueMethod = ReflectUtil.getMethod(AnnotationForTest.class, "value");
|
||||
final CacheableAnnotationAttribute valueAttribute = new CacheableAnnotationAttribute(annotation, valueMethod);
|
||||
final Method nameMethod = ReflectUtil.getMethod(AnnotationForTest.class, "name");
|
||||
final CacheableAnnotationAttribute nameAttribute = new CacheableAnnotationAttribute(annotation, nameMethod);
|
||||
final MirroredAnnotationAttribute nameAnnotationAttribute = new MirroredAnnotationAttribute(nameAttribute, valueAttribute);
|
||||
|
||||
// 值处理
|
||||
Assert.assertEquals("name", nameAnnotationAttribute.getValue());
|
||||
Assert.assertFalse(nameAnnotationAttribute.isValueEquivalentToDefaultValue());
|
||||
Assert.assertTrue(nameAnnotationAttribute.isWrapped());
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface AnnotationForTest {
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
}
|
||||
|
||||
@AnnotationForTest(value = "name")
|
||||
static class ClassForTest1 {}
|
||||
|
||||
@AnnotationForTest
|
||||
static class ClassForTest2 {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class SynthesizedAnnotationSelectorTest {
|
||||
|
||||
@Test
|
||||
public void chooseTest() {
|
||||
final SynthesizedAnnotationSelector.NearestAndOldestPrioritySelector selector = (SynthesizedAnnotationSelector.NearestAndOldestPrioritySelector)SynthesizedAnnotationSelector.NEAREST_AND_OLDEST_PRIORITY;
|
||||
|
||||
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 1);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(1, 0);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nearestAndNewestPriorityTest() {
|
||||
final SynthesizedAnnotationSelector.NearestAndNewestPrioritySelector selector = (SynthesizedAnnotationSelector.NearestAndNewestPrioritySelector)SynthesizedAnnotationSelector.NEAREST_AND_NEWEST_PRIORITY;
|
||||
|
||||
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 1);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
annotation2 = new TestSynthesizedAnnotation(1, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void farthestAndOldestPriorityTest() {
|
||||
final SynthesizedAnnotationSelector.FarthestAndOldestPrioritySelector selector = (SynthesizedAnnotationSelector.FarthestAndOldestPrioritySelector)SynthesizedAnnotationSelector.FARTHEST_AND_OLDEST_PRIORITY;
|
||||
|
||||
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 1);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
annotation2 = new TestSynthesizedAnnotation(1, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void farthestAndNewestPriorityTest() {
|
||||
final SynthesizedAnnotationSelector.FarthestAndNewestPrioritySelector selector = (SynthesizedAnnotationSelector.FarthestAndNewestPrioritySelector)SynthesizedAnnotationSelector.FARTHEST_AND_NEWEST_PRIORITY;
|
||||
|
||||
TestSynthesizedAnnotation annotation1 = new TestSynthesizedAnnotation(0, 0);
|
||||
TestSynthesizedAnnotation annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(0, 1);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation2, selector.choose(annotation1, annotation2));
|
||||
|
||||
annotation1 = new TestSynthesizedAnnotation(1, 0);
|
||||
annotation2 = new TestSynthesizedAnnotation(0, 0);
|
||||
Assert.assertEquals(annotation1, selector.choose(annotation1, annotation2));
|
||||
}
|
||||
|
||||
static class TestSynthesizedAnnotation implements SynthesizedAnnotation {
|
||||
|
||||
private final int verticalDistance;
|
||||
private final int horizontalDistance;
|
||||
|
||||
public TestSynthesizedAnnotation(int verticalDistance, int horizontalDistance) {
|
||||
this.verticalDistance = verticalDistance;
|
||||
this.horizontalDistance = horizontalDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRoot() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalDistance() {
|
||||
return this.verticalDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalDistance() {
|
||||
return this.horizontalDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAttribute(String attributeName, Class<?> returnType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AnnotationAttribute> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String attributeName, AnnotationAttribute attribute) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceAttribute(String attributeName, UnaryOperator<AnnotationAttribute> operator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 合成注解{@link SyntheticMetaAnnotation}的测试用例
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public class SyntheticMetaAnnotationTest {
|
||||
|
||||
@Test
|
||||
public void testSynthesisAnnotation() {
|
||||
ChildAnnotation rootAnnotation = AnnotatedClass.class.getAnnotation(ChildAnnotation.class);
|
||||
SyntheticMetaAnnotation syntheticMetaAnnotation = new SyntheticMetaAnnotation(rootAnnotation);
|
||||
Assert.assertEquals(syntheticMetaAnnotation.getSource(), rootAnnotation);
|
||||
Assert.assertEquals(syntheticMetaAnnotation.annotationType(), SyntheticMetaAnnotation.class);
|
||||
Assert.assertEquals(1, syntheticMetaAnnotation.getDeclaredAnnotations().length);
|
||||
Assert.assertEquals(syntheticMetaAnnotation.getDeclaredAnnotations()[0], rootAnnotation);
|
||||
Assert.assertEquals(3, syntheticMetaAnnotation.getAnnotations().length);
|
||||
|
||||
Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValue", String.class));
|
||||
Assert.assertEquals("Child!", syntheticMetaAnnotation.getAttribute("childValueAlias", String.class));
|
||||
Assert.assertEquals("Child's Parent!", syntheticMetaAnnotation.getAttribute("parentValue", String.class));
|
||||
Assert.assertEquals("Child's GrandParent!", syntheticMetaAnnotation.getAttribute("grandParentValue", String.class));
|
||||
|
||||
ChildAnnotation childAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ChildAnnotation.class);
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ChildAnnotation.class));
|
||||
Assert.assertNotNull(childAnnotation);
|
||||
Assert.assertEquals("Child!", childAnnotation.childValue());
|
||||
Assert.assertEquals("Child!", childAnnotation.childValueAlias());
|
||||
Assert.assertEquals(childAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(childAnnotation));
|
||||
|
||||
ParentAnnotation parentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(ParentAnnotation.class);
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(ParentAnnotation.class));
|
||||
Assert.assertNotNull(parentAnnotation);
|
||||
Assert.assertEquals("Child's Parent!", parentAnnotation.parentValue());
|
||||
Assert.assertEquals("java.lang.Void", parentAnnotation.grandParentType());
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(parentAnnotation));
|
||||
|
||||
GrandParentAnnotation grandParentAnnotation = syntheticMetaAnnotation.syntheticAnnotation(GrandParentAnnotation.class);
|
||||
Assert.assertTrue(syntheticMetaAnnotation.isAnnotationPresent(GrandParentAnnotation.class));
|
||||
Assert.assertNotNull(grandParentAnnotation);
|
||||
Assert.assertEquals("Child's GrandParent!", grandParentAnnotation.grandParentValue());
|
||||
Assert.assertEquals(grandParentAnnotation.grandParentType(), Integer.class);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> new SyntheticMetaAnnotation(grandParentAnnotation));
|
||||
}
|
||||
|
||||
// 注解结构如下:
|
||||
// AnnotatedClass -> @ChildAnnotation -> @ParentAnnotation -> @GrandParentAnnotation
|
||||
// -> @GrandParentAnnotation
|
||||
@ChildAnnotation(childValueAlias = "Child!", grandParentType = Integer.class)
|
||||
static class AnnotatedClass {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.ANNOTATION_TYPE })
|
||||
@interface GrandParentAnnotation {
|
||||
String grandParentValue() default "";
|
||||
Class<?> grandParentType() default Void.class;
|
||||
}
|
||||
|
||||
@GrandParentAnnotation(grandParentValue = "Parent's GrandParent!") // 覆盖元注解@GrandParentAnnotation的属性
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
@interface ParentAnnotation {
|
||||
String parentValue() default "";
|
||||
String grandParentType() default "java.lang.Void";
|
||||
}
|
||||
|
||||
@GrandParentAnnotation(grandParentValue = "Child's GrandParent!") // 重复的元注解,靠近根注解的优先级高
|
||||
@ParentAnnotation(parentValue = "Child's Parent!") // 覆盖元注解@ParentAnnotation的属性
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@interface ChildAnnotation {
|
||||
String childValueAlias() default "";
|
||||
@Alias("childValueAlias")
|
||||
String childValue() default "";
|
||||
Class<?> grandParentType() default Void.class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class TypeAnnotationScannerTest {
|
||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||
|
||||
// 不查找父类
|
||||
scanner = new TypeAnnotationScanner().setIncludeSupperClass(false);
|
||||
scanner = new TypeAnnotationScanner().setIncludeSuperClass(false);
|
||||
annotations = scanner.getAnnotations(Example.class);
|
||||
Assert.assertEquals(1, annotations.size());
|
||||
annotations.forEach(a -> Assert.assertEquals(a.annotationType(), AnnotationForScannerTest.class));
|
||||
@@ -88,7 +88,7 @@ public class TypeAnnotationScannerTest {
|
||||
// 不查找父类
|
||||
map.clear();
|
||||
new TypeAnnotationScanner()
|
||||
.setIncludeSupperClass(false)
|
||||
.setIncludeSuperClass(false)
|
||||
.scan(
|
||||
(index, annotation) -> map.computeIfAbsent(index, i -> new ArrayList<>()).add(annotation),
|
||||
Example.class, null
|
||||
|
||||
Reference in New Issue
Block a user