mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
提取获取注解属性值相关逻辑至注解属性值提取器
This commit is contained in:
parent
931965301b
commit
d873b6e9da
@ -8,6 +8,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -27,6 +28,11 @@ public abstract class AbstractAnnotationSynthesizer<T> implements AnnotationSynt
|
||||
*/
|
||||
protected final Map<Class<? extends Annotation>, SynthesizedAnnotation> synthesizedAnnotationMap;
|
||||
|
||||
/**
|
||||
* 已经合成过的注解对象
|
||||
*/
|
||||
private final Map<Class<? extends Annotation>, Annotation> synthesizedProxyAnnotations;
|
||||
|
||||
/**
|
||||
* 合成注解选择器
|
||||
*/
|
||||
@ -38,7 +44,7 @@ public abstract class AbstractAnnotationSynthesizer<T> implements AnnotationSynt
|
||||
protected final Collection<SynthesizedAnnotationPostProcessor> postProcessors;
|
||||
|
||||
/**
|
||||
* 基于指定根注解,为其层级结构中的全部注解构造一个合成注解
|
||||
* 构造一个注解合成器
|
||||
*
|
||||
* @param source 当前查找的注解对象
|
||||
* @param annotationSelector 合成注解选择器
|
||||
@ -55,6 +61,7 @@ public abstract class AbstractAnnotationSynthesizer<T> implements AnnotationSynt
|
||||
this.postProcessors = CollUtil.unmodifiable(
|
||||
CollUtil.sort(annotationPostProcessors, Comparator.comparing(SynthesizedAnnotationPostProcessor::order))
|
||||
);
|
||||
this.synthesizedProxyAnnotations = new LinkedHashMap<>();
|
||||
this.synthesizedAnnotationMap = MapUtil.unmodifiable(loadAnnotations());
|
||||
annotationPostProcessors.forEach(processor ->
|
||||
synthesizedAnnotationMap.values().forEach(synthesized -> processor.process(synthesized, this))
|
||||
@ -136,13 +143,14 @@ public abstract class AbstractAnnotationSynthesizer<T> implements AnnotationSynt
|
||||
* @param <A> 注解类型
|
||||
* @return 类型
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <A extends Annotation> A synthesize(Class<A> annotationType) {
|
||||
SynthesizedAnnotation synthesizedAnnotation = synthesizedAnnotationMap.get(annotationType);
|
||||
if (ObjectUtil.isNull(synthesizedAnnotation)) {
|
||||
return null;
|
||||
}
|
||||
return synthesize(annotationType, synthesizedAnnotation);
|
||||
return (A)synthesizedProxyAnnotations.computeIfAbsent(annotationType, type -> {
|
||||
final SynthesizedAnnotation synthesizedAnnotation = synthesizedAnnotationMap.get(annotationType);
|
||||
return ObjectUtil.isNull(synthesizedAnnotation) ?
|
||||
null : synthesize(annotationType, synthesizedAnnotation);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.hutool.core.annotation;
|
||||
|
||||
/**
|
||||
* 表示一个可以从当前接口的实现类中,获得特定的属性值
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AnnotationAttributeValueProvider {
|
||||
|
||||
/**
|
||||
* 获取注解属性值
|
||||
*
|
||||
* @param attributeName 属性名称
|
||||
* @param attributeType 属性类型
|
||||
* @return 注解属性值
|
||||
*/
|
||||
Object getAttributeValue(String attributeName, Class<?> attributeType);
|
||||
|
||||
}
|
@ -355,7 +355,7 @@ public class AnnotationUtil {
|
||||
*/
|
||||
public static <T extends Annotation> T getSynthesizedAnnotation(Annotation annotation, Class<T> annotationType) {
|
||||
// TODO 缓存合成注解信息,避免重复解析
|
||||
return SynthesizedAggregateAnnotation.of(annotation).synthesize(annotationType);
|
||||
return SynthesizedAggregateAnnotation.from(annotation).synthesize(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,12 +16,13 @@ import java.util.stream.Stream;
|
||||
* {@link SynthesizedAnnotation}的基本实现
|
||||
*
|
||||
* @param <R> 根对象类型
|
||||
* @param <T> 注解类型
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public abstract class AbstractSynthesizedAnnotation<R> implements Annotation, SynthesizedAnnotation {
|
||||
public class GenericSynthesizedAnnotation<R, T extends Annotation> implements Annotation, SynthesizedAnnotation {
|
||||
|
||||
private final R root;
|
||||
private final Annotation annotation;
|
||||
private final T annotation;
|
||||
private final Map<String, AnnotationAttribute> attributeMethodCaches;
|
||||
private final int verticalDistance;
|
||||
private final int horizontalDistance;
|
||||
@ -34,8 +35,8 @@ public abstract class AbstractSynthesizedAnnotation<R> implements Annotation, Sy
|
||||
* @param verticalDistance 距离根对象的水平距离
|
||||
* @param horizontalDistance 距离根对象的垂直距离
|
||||
*/
|
||||
protected AbstractSynthesizedAnnotation(
|
||||
R root, Annotation annotation, int verticalDistance, int horizontalDistance) {
|
||||
protected GenericSynthesizedAnnotation(
|
||||
R root, T annotation, int verticalDistance, int horizontalDistance) {
|
||||
this.root = root;
|
||||
this.annotation = annotation;
|
||||
this.verticalDistance = verticalDistance;
|
||||
@ -143,7 +144,7 @@ public abstract class AbstractSynthesizedAnnotation<R> implements Annotation, Sy
|
||||
* @return 注解对象
|
||||
*/
|
||||
@Override
|
||||
public Annotation getAnnotation() {
|
||||
public T getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@ -179,4 +180,18 @@ public abstract class AbstractSynthesizedAnnotation<R> implements Annotation, Sy
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注解属性值
|
||||
*
|
||||
* @param attributeName 属性名称
|
||||
* @param attributeType 属性类型
|
||||
* @return 注解属性值
|
||||
*/
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return Opt.ofNullable(attributeMethodCaches.get(attributeName))
|
||||
.filter(method -> ClassUtil.isAssignable(attributeType, method.getAttributeType()))
|
||||
.map(AnnotationAttribute::getValue)
|
||||
.get();
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ import java.lang.annotation.Annotation;
|
||||
* @see SynthesizedAnnotationPostProcessor
|
||||
* @see SynthesizedMetaAggregateAnnotation
|
||||
*/
|
||||
public interface SynthesizedAggregateAnnotation extends AggregateAnnotation, Hierarchical, AnnotationSynthesizer {
|
||||
public interface SynthesizedAggregateAnnotation extends AggregateAnnotation, Hierarchical, AnnotationSynthesizer, AnnotationAttributeValueProvider {
|
||||
|
||||
// ================== hierarchical ==================
|
||||
|
||||
@ -96,7 +96,8 @@ public interface SynthesizedAggregateAnnotation extends AggregateAnnotation, Hie
|
||||
* @param attributeType 属性类型
|
||||
* @return 属性值
|
||||
*/
|
||||
Object getAttribute(String attributeName, Class<?> attributeType);
|
||||
@Override
|
||||
Object getAttributeValue(String attributeName, Class<?> attributeType);
|
||||
|
||||
/**
|
||||
* 基于指定根注解,构建包括其元注解在内的合成注解
|
||||
@ -105,7 +106,7 @@ public interface SynthesizedAggregateAnnotation extends AggregateAnnotation, Hie
|
||||
* @param <T> 注解类型
|
||||
* @return 合成注解
|
||||
*/
|
||||
static <T extends Annotation> SynthesizedAggregateAnnotation of(T rootAnnotation) {
|
||||
static <T extends Annotation> SynthesizedAggregateAnnotation from(T rootAnnotation) {
|
||||
return new SynthesizedMetaAggregateAnnotation(rootAnnotation);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import java.util.function.UnaryOperator;
|
||||
* @author huangchengxing
|
||||
* @see SynthesizedAggregateAnnotation
|
||||
*/
|
||||
public interface SynthesizedAnnotation extends Annotation, Hierarchical {
|
||||
public interface SynthesizedAnnotation extends Annotation, Hierarchical, AnnotationAttributeValueProvider {
|
||||
|
||||
/**
|
||||
* 获取被合成的注解对象
|
||||
|
@ -19,25 +19,18 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 合成注解代理类
|
||||
* 合成注解代理类,用于为{@link SynthesizedAnnotation}生成对应的合成注解代理对象
|
||||
*
|
||||
* @author huangchengxing
|
||||
* @see SynthesizedAnnotation
|
||||
* @see AnnotationAttributeValueProvider
|
||||
*/
|
||||
class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
public class SynthesizedAnnotationProxy implements InvocationHandler {
|
||||
|
||||
private final SynthesizedAggregateAnnotation aggregateAnnotation;
|
||||
private final AnnotationAttributeValueProvider annotationAttributeValueProvider;
|
||||
private final SynthesizedAnnotation annotation;
|
||||
private final Map<String, BiFunction<Method, Object[], Object>> methods;
|
||||
|
||||
SyntheticAnnotationProxy(SynthesizedAggregateAnnotation aggregateAnnotation, SynthesizedAnnotation annotation) {
|
||||
Assert.notNull(aggregateAnnotation, "aggregateAnnotation must not null");
|
||||
Assert.notNull(annotation, "annotation must not null");
|
||||
this.aggregateAnnotation = aggregateAnnotation;
|
||||
this.annotation = annotation;
|
||||
this.methods = new HashMap<>(9);
|
||||
loadMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个代理注解,生成的代理对象将是{@link SyntheticProxyAnnotation}与指定的注解类的子类。
|
||||
* <ul>
|
||||
@ -45,17 +38,17 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
* <li>当作为{@link SyntheticProxyAnnotation}或{@link SynthesizedAnnotation}使用时,将可以获得原始注解实例的相关信息;</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @param aggregateAnnotation 合成注解
|
||||
* @param annotationType 注解类型
|
||||
* @param annotationAttributeValueProvider 注解属性值获取器
|
||||
* @return 代理注解
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends Annotation> T create(
|
||||
Class<T> annotationType, SynthesizedAggregateAnnotation aggregateAnnotation, SynthesizedAnnotation annotation) {
|
||||
public static <T extends Annotation> T create(
|
||||
Class<T> annotationType, AnnotationAttributeValueProvider annotationAttributeValueProvider, SynthesizedAnnotation annotation) {
|
||||
if (ObjectUtil.isNull(annotation)) {
|
||||
return null;
|
||||
}
|
||||
final SyntheticAnnotationProxy proxyHandler = new SyntheticAnnotationProxy(aggregateAnnotation, annotation);
|
||||
final SynthesizedAnnotationProxy proxyHandler = new SynthesizedAnnotationProxy(annotationAttributeValueProvider, annotation);
|
||||
if (ObjectUtil.isNull(annotation)) {
|
||||
return null;
|
||||
}
|
||||
@ -66,8 +59,23 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
);
|
||||
}
|
||||
|
||||
static boolean isProxyAnnotation(Class<?> targetClass) {
|
||||
return ClassUtil.isAssignable(SyntheticProxyAnnotation.class, targetClass);
|
||||
/**
|
||||
* 该类是否为通过{@link SynthesizedAnnotationProxy}生成的代理类
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isProxyAnnotation(Class<?> annotationType) {
|
||||
return ClassUtil.isAssignable(SyntheticProxyAnnotation.class, annotationType);
|
||||
}
|
||||
|
||||
SynthesizedAnnotationProxy(AnnotationAttributeValueProvider annotationAttributeValueProvider, SynthesizedAnnotation annotation) {
|
||||
Assert.notNull(annotationAttributeValueProvider, "annotationAttributeValueProvider must not null");
|
||||
Assert.notNull(annotation, "annotation must not null");
|
||||
this.annotationAttributeValueProvider = annotationAttributeValueProvider;
|
||||
this.annotation = annotation;
|
||||
this.methods = new HashMap<>(9);
|
||||
loadMethods();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +90,6 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
void loadMethods() {
|
||||
methods.put("toString", (method, args) -> proxyToString());
|
||||
methods.put("hashCode", (method, args) -> proxyHashCode());
|
||||
methods.put("getSynthesizedAnnotationAggregator", (method, args) -> proxyGetSynthesizedAnnotationAggregator());
|
||||
methods.put("getSynthesizedAnnotation", (method, args) -> proxyGetSynthesizedAnnotation());
|
||||
methods.put("getRoot", (method, args) -> annotation.getRoot());
|
||||
methods.put("getVerticalDistance", (method, args) -> annotation.getVerticalDistance());
|
||||
@ -102,17 +109,15 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
private String proxyToString() {
|
||||
final String attributes = Stream.of(ClassUtil.getDeclaredMethods(annotation.getAnnotation().annotationType()))
|
||||
.filter(AnnotationUtil::isAttributeMethod)
|
||||
.map(method -> CharSequenceUtil.format("{}={}", method.getName(), aggregateAnnotation.getAttribute(method.getName(), method.getReturnType())))
|
||||
.map(method -> CharSequenceUtil.format(
|
||||
"{}={}", method.getName(), proxyAttributeValue(method))
|
||||
)
|
||||
.collect(Collectors.joining(", "));
|
||||
return CharSequenceUtil.format("@{}({})", annotation.annotationType().getName(), attributes);
|
||||
}
|
||||
|
||||
private int proxyHashCode() {
|
||||
return Objects.hash(aggregateAnnotation, annotation);
|
||||
}
|
||||
|
||||
private Object proxyGetSynthesizedAnnotationAggregator() {
|
||||
return aggregateAnnotation;
|
||||
return Objects.hash(annotationAttributeValueProvider, annotation);
|
||||
}
|
||||
|
||||
private Object proxyGetSynthesizedAnnotation() {
|
||||
@ -120,7 +125,7 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
}
|
||||
|
||||
private Object proxyAttributeValue(Method attributeMethod) {
|
||||
return aggregateAnnotation.getAttribute(attributeMethod.getName(), attributeMethod.getReturnType());
|
||||
return annotationAttributeValueProvider.getAttributeValue(attributeMethod.getName(), attributeMethod.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,13 +135,6 @@ class SyntheticAnnotationProxy implements InvocationHandler {
|
||||
*/
|
||||
interface SyntheticProxyAnnotation extends SynthesizedAnnotation {
|
||||
|
||||
/**
|
||||
* 获取该注解所属的合成注解
|
||||
*
|
||||
* @return 合成注解
|
||||
*/
|
||||
SynthesizedAggregateAnnotation getSynthesizedAnnotationAggregator();
|
||||
|
||||
/**
|
||||
* 获取该代理注解对应的已合成注解
|
||||
*
|
@ -37,7 +37,7 @@ import java.util.Map;
|
||||
* </ul>
|
||||
* 若用户需要自行扩展,则需要保证上述三个处理器被正确注入当前实例。
|
||||
*
|
||||
* <p>{@link SynthesizedMetaAggregateAnnotation}支持通过{@link #getAttribute(String, Class)},
|
||||
* <p>{@link SynthesizedMetaAggregateAnnotation}支持通过{@link #getAttributeValue(String, Class)},
|
||||
* 或通过{@link #synthesize(Class)}获得注解代理对象后获取指定类型的注解属性值,
|
||||
* 返回的属性值将根据合成注解中对应原始注解属性上的{@link Alias}与{@link Link}注解而有所变化。
|
||||
* 通过当前实例获取属性值时,将经过{@link SynthesizedAnnotationAttributeProcessor}的处理。<br>
|
||||
@ -169,7 +169,7 @@ public class SynthesizedMetaAggregateAnnotation extends AbstractAnnotationSynthe
|
||||
*/
|
||||
@Override
|
||||
protected Map<Class<? extends Annotation>, SynthesizedAnnotation> loadAnnotations() {
|
||||
Assert.isFalse(SyntheticAnnotationProxy.isProxyAnnotation(source.getClass()), "source [{}] has been synthesized");
|
||||
Assert.isFalse(SynthesizedAnnotationProxy.isProxyAnnotation(source.getClass()), "source [{}] has been synthesized");
|
||||
Map<Class<? extends Annotation>, SynthesizedAnnotation> annotationMap = new LinkedHashMap<>();
|
||||
annotationMap.put(source.annotationType(), new MetaAnnotation(source, source, 0, 0));
|
||||
new MetaAnnotationScanner().scan(
|
||||
@ -206,7 +206,7 @@ public class SynthesizedMetaAggregateAnnotation extends AbstractAnnotationSynthe
|
||||
* @return 属性
|
||||
*/
|
||||
@Override
|
||||
public Object getAttribute(String attributeName, Class<?> attributeType) {
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return attributeProcessor.getAttributeValue(attributeName, attributeType, synthesizedAnnotationMap.values());
|
||||
}
|
||||
|
||||
@ -254,11 +254,11 @@ public class SynthesizedMetaAggregateAnnotation extends AbstractAnnotationSynthe
|
||||
*
|
||||
* @param annotationType 注解类型
|
||||
* @return 合成注解对象
|
||||
* @see SyntheticAnnotationProxy#create(Class, SynthesizedAggregateAnnotation, SynthesizedAnnotation)
|
||||
* @see SynthesizedAnnotationProxy#create(Class, AnnotationAttributeValueProvider, SynthesizedAnnotation)
|
||||
*/
|
||||
@Override
|
||||
public <T extends Annotation> T synthesize(Class<T> annotationType, SynthesizedAnnotation annotation) {
|
||||
return SyntheticAnnotationProxy.create(annotationType, this, annotation);
|
||||
return SynthesizedAnnotationProxy.create(annotationType, this, annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +266,7 @@ public class SynthesizedMetaAggregateAnnotation extends AbstractAnnotationSynthe
|
||||
*
|
||||
* @author huangchengxing
|
||||
*/
|
||||
public static class MetaAnnotation extends AbstractSynthesizedAnnotation<Annotation> {
|
||||
public static class MetaAnnotation extends GenericSynthesizedAnnotation<Annotation, Annotation> {
|
||||
|
||||
/**
|
||||
* 创建一个合成注解
|
||||
|
@ -108,7 +108,7 @@ public class AliasAnnotationPostProcessorTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attributeName, Class<?> attributeType) {
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -185,6 +185,11 @@ public class AliasAnnotationPostProcessorTest {
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class AliasLinkAnnotationPostProcessorTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attributeName, Class<?> attributeType) {
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -213,6 +213,11 @@ public class AliasLinkAnnotationPostProcessorTest {
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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("测试")
|
||||
|
@ -90,6 +90,10 @@ public class CacheableSynthesizedAnnotationAttributeProcessorTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class MirrorLinkAnnotationPostProcessorTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attributeName, Class<?> attributeType) {
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -188,6 +188,11 @@ public class MirrorLinkAnnotationPostProcessorTest {
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -136,6 +136,11 @@ public class SynthesizedAnnotationSelectorTest {
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttributeValue(String attributeName, Class<?> attributeType) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,10 +60,10 @@ public class SyntheticMetaAnnotationTest {
|
||||
Assert.assertEquals(syntheticMetaAnnotation.annotationType(), SynthesizedMetaAggregateAnnotation.class);
|
||||
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));
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user