/** * Retrieve the given annotation's attributes as a {@link Map}. * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} * with the {@code nestedAnnotationsAsMap} parameter set to {@code false}. * <p>Note: This method actually returns an {@link AnnotationAttributes} instance. * However, the {@code Map} signature has been preserved for binary compatibility. * @param annotation the annotation to retrieve the attributes for * @param classValuesAsString whether to convert Class references into Strings (for * compatibility with {@link org.springframework.core.type.AnnotationMetadata}) * or to preserve them as Class references * @return the Map of annotation attributes, with attribute names as keys and * corresponding attribute values as values (never {@code null}) * @see #getAnnotationAttributes(Annotation, boolean, boolean) */ public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) { return getAnnotationAttributes(annotation, classValuesAsString, false); }
/** * Retrieve the given annotation's attributes as a {@link Map}, preserving all * attribute types. * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters * set to {@code false}. * <p>Note: This method actually returns an {@link AnnotationAttributes} instance. * However, the {@code Map} signature has been preserved for binary compatibility. * @param annotation the annotation to retrieve the attributes for * @return the Map of annotation attributes, with attribute names as keys and * corresponding attribute values as values (never {@code null}) * @see #getAnnotationAttributes(AnnotatedElement, Annotation) * @see #getAnnotationAttributes(Annotation, boolean, boolean) * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean) */ public static Map<String, Object> getAnnotationAttributes(Annotation annotation) { return getAnnotationAttributes(null, annotation); }
/** * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map. * <p>This method provides fully recursive annotation reading capabilities on par with * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}. * @param annotation the annotation to retrieve the attributes for * @param classValuesAsString whether to convert Class references into Strings (for * compatibility with {@link org.springframework.core.type.AnnotationMetadata}) * or to preserve them as Class references * @param nestedAnnotationsAsMap whether to convert nested annotations into * {@link AnnotationAttributes} maps (for compatibility with * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as * {@code Annotation} instances * @return the annotation attributes (a specialized Map) with attribute names as keys * and corresponding attribute values as values (never {@code null}) * @since 3.1.1 */ public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) { return getAnnotationAttributes(null, annotation, classValuesAsString, nestedAnnotationsAsMap); }
/** * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map. * <p>Equivalent to calling {@link #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)} * with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters * set to {@code false}. * @param annotatedElement the element that is annotated with the supplied annotation; * may be {@code null} if unknown * @param annotation the annotation to retrieve the attributes for * @return the annotation attributes (a specialized Map) with attribute names as keys * and corresponding attribute values as values (never {@code null}) * @since 4.2 * @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean) */ public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation) { return getAnnotationAttributes(annotatedElement, annotation, false, false); }
/** * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map. * <p>This method provides fully recursive annotation reading capabilities on par with * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}. * @param annotatedElement the element that is annotated with the supplied annotation; * may be {@code null} if unknown * @param annotation the annotation to retrieve the attributes for * @param classValuesAsString whether to convert Class references into Strings (for * compatibility with {@link org.springframework.core.type.AnnotationMetadata}) * or to preserve them as Class references * @param nestedAnnotationsAsMap whether to convert nested annotations into * {@link AnnotationAttributes} maps (for compatibility with * {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as * {@code Annotation} instances * @return the annotation attributes (a specialized Map) with attribute names as keys * and corresponding attribute values as values (never {@code null}) * @since 4.2 */ public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) { return getAnnotationAttributes( (Object) annotatedElement, annotation, classValuesAsString, nestedAnnotationsAsMap); }
@Override @Nullable public Object process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) { AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes( annotation, classValuesAsString, nestedAnnotationsAsMap); annotationAttributes.forEach(attributesMap::add); return CONTINUE; } });
public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) { return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false)); }
public TransactionAttribute parseTransactionAnnotation(Transactional ann) { return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false)); }
@Override @Nullable public Object process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) { AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes( annotation, classValuesAsString, nestedAnnotationsAsMap); annotationAttributes.forEach(attributesMap::add); return CONTINUE; } });
private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) { Class<? extends Annotation> annotationType = annotation.annotationType(); String annotationName = annotationType.getName(); if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName) && visited.add(annotation)) { try { // Only do attribute scanning for public annotations; we'd run into // IllegalAccessExceptions otherwise, and we don't want to mess with // accessibility in a SecurityManager environment. if (Modifier.isPublic(annotationType.getModifiers())) { this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true)); } for (Annotation metaMetaAnnotation : annotationType.getAnnotations()) { recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation); } } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to introspect meta-annotations on " + annotation + ": " + ex); } } } }
private String formatAnnotation(Annotation annotation) { Map<String, Object> map = AnnotationUtils.getAnnotationAttributes(annotation); map.forEach((key, value) -> { if (value.equals(DEFAULT_VALUE_NONE)) { map.put(key, "NONE"); } }); return annotation.annotationType().getName() + map; }
private String formatAnnotation(Annotation annotation) { Map<String, Object> map = AnnotationUtils.getAnnotationAttributes(annotation); map.forEach((key, value) -> { if (value.equals(DEFAULT_VALUE_NONE)) { map.put(key, "NONE"); } }); return annotation.annotationType().getName() + map; }
if (defaultValue != null && !attributes.containsKey(attributeName)) { if (defaultValue instanceof Annotation) { defaultValue = getAnnotationAttributes((Annotation) defaultValue, false, true); AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length]; for (int i = 0; i < realAnnotations.length; i++) { mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], false, true);
@Test public void getAnnotationAttributesWithAttributeAliasesWithDifferentValues() throws Exception { exception.expect(AnnotationConfigurationException.class); exception.expectMessage(containsString("attribute 'value' and its alias 'path'")); exception.expectMessage(containsString("values of [{/enigma}] and [{/test}]")); Method method = WebController.class.getMethod("handleMappedWithDifferentPathAndValueAttributes"); WebMapping webMapping = method.getAnnotation(WebMapping.class); getAnnotationAttributes(webMapping); }
@Test public void getAnnotationAttributesWithNestedAnnotations() { ComponentScan componentScan = ComponentScanClass.class.getAnnotation(ComponentScan.class); assertNotNull(componentScan); AnnotationAttributes attributes = getAnnotationAttributes(ComponentScanClass.class, componentScan); assertNotNull(attributes); assertEquals(ComponentScan.class, attributes.annotationType()); Filter[] filters = attributes.getAnnotationArray("excludeFilters", Filter.class); assertNotNull(filters); List<String> patterns = stream(filters).map(Filter::pattern).collect(toList()); assertEquals(asList("*Foo", "*Bar"), patterns); }
@Test @SuppressWarnings("unchecked") public void synthesizeAnnotationFromMapWithNestedArrayOfMaps() throws Exception { ComponentScan componentScan = ComponentScanClass.class.getAnnotation(ComponentScan.class); assertNotNull(componentScan); AnnotationAttributes attributes = getAnnotationAttributes(ComponentScanClass.class, componentScan, false, true); assertNotNull(attributes); assertEquals(ComponentScan.class, attributes.annotationType()); Map<String, Object>[] filters = (Map[]) attributes.get("excludeFilters"); assertNotNull(filters); List<String> patterns = stream(filters).map(m -> (String) m.get("pattern")).collect(toList()); assertEquals(asList("*Foo", "*Bar"), patterns); // Modify nested maps filters[0].put("pattern", "newFoo"); filters[0].put("enigma", 42); filters[1].put("pattern", "newBar"); filters[1].put("enigma", 42); ComponentScan synthesizedComponentScan = synthesizeAnnotation(attributes, ComponentScan.class, ComponentScanClass.class); assertNotNull(synthesizedComponentScan); assertNotSame(componentScan, synthesizedComponentScan); patterns = stream(synthesizedComponentScan.excludeFilters()).map(Filter::pattern).collect(toList()); assertEquals(asList("newFoo", "newBar"), patterns); }
@Test public void getAnnotationAttributesWithoutAttributeAliases() { Component component = WebController.class.getAnnotation(Component.class); assertNotNull(component); AnnotationAttributes attributes = (AnnotationAttributes) getAnnotationAttributes(component); assertNotNull(attributes); assertEquals("value attribute: ", "webController", attributes.getString(VALUE)); assertEquals(Component.class, attributes.annotationType()); }
@Test public void getAnnotationAttributesWithAttributeAliases() throws Exception { Method method = WebController.class.getMethod("handleMappedWithValueAttribute"); WebMapping webMapping = method.getAnnotation(WebMapping.class); AnnotationAttributes attributes = (AnnotationAttributes) getAnnotationAttributes(webMapping); assertNotNull(attributes); assertEquals(WebMapping.class, attributes.annotationType()); assertEquals("name attribute: ", "foo", attributes.getString("name")); assertArrayEquals("value attribute: ", asArray("/test"), attributes.getStringArray(VALUE)); assertArrayEquals("path attribute: ", asArray("/test"), attributes.getStringArray("path")); method = WebController.class.getMethod("handleMappedWithPathAttribute"); webMapping = method.getAnnotation(WebMapping.class); attributes = (AnnotationAttributes) getAnnotationAttributes(webMapping); assertNotNull(attributes); assertEquals(WebMapping.class, attributes.annotationType()); assertEquals("name attribute: ", "bar", attributes.getString("name")); assertArrayEquals("value attribute: ", asArray("/test"), attributes.getStringArray(VALUE)); assertArrayEquals("path attribute: ", asArray("/test"), attributes.getStringArray("path")); }
@Test @SuppressWarnings("unchecked") public void synthesizeAnnotationFromMapWithNestedMap() throws Exception { ComponentScanSingleFilter componentScan = ComponentScanSingleFilterClass.class.getAnnotation(ComponentScanSingleFilter.class); assertNotNull(componentScan); assertEquals("value from ComponentScan: ", "*Foo", componentScan.value().pattern()); AnnotationAttributes attributes = getAnnotationAttributes( ComponentScanSingleFilterClass.class, componentScan, false, true); assertNotNull(attributes); assertEquals(ComponentScanSingleFilter.class, attributes.annotationType()); Map<String, Object> filterMap = (Map<String, Object>) attributes.get("value"); assertNotNull(filterMap); assertEquals("*Foo", filterMap.get("pattern")); // Modify nested map filterMap.put("pattern", "newFoo"); filterMap.put("enigma", 42); ComponentScanSingleFilter synthesizedComponentScan = synthesizeAnnotation( attributes, ComponentScanSingleFilter.class, ComponentScanSingleFilterClass.class); assertNotNull(synthesizedComponentScan); assertNotSame(componentScan, synthesizedComponentScan); assertEquals("value from synthesized ComponentScan: ", "newFoo", synthesizedComponentScan.value().pattern()); }
@Test public void synthesizeAnnotationFromAnnotationAttributesWithoutAttributeAliases() throws Exception { // 1) Get an annotation Component component = WebController.class.getAnnotation(Component.class); assertNotNull(component); // 2) Convert the annotation into AnnotationAttributes AnnotationAttributes attributes = getAnnotationAttributes(WebController.class, component); assertNotNull(attributes); // 3) Synthesize the AnnotationAttributes back into an annotation Component synthesizedComponent = synthesizeAnnotation(attributes, Component.class, WebController.class); assertNotNull(synthesizedComponent); // 4) Verify that the original and synthesized annotations are equivalent assertNotSame(component, synthesizedComponent); assertEquals(component, synthesizedComponent); assertEquals("value from component: ", "webController", component.value()); assertEquals("value from synthesized component: ", "webController", synthesizedComponent.value()); }