@Override protected AnnotationAttributeExtractor<?> createExtractorFor(Class<?> clazz, String expected, Class<? extends Annotation> annotationType) { Map<String, Object> attributes = Collections.singletonMap(expected, expected); return new MapAnnotationAttributeExtractor(attributes, annotationType, clazz); }
@Override @Nullable protected Object getRawAttributeValue(String attributeName) { return getSource().get(attributeName); }
/** * Construct a new {@code MapAnnotationAttributeExtractor}. * <p>The supplied map must contain a key-value pair for every attribute * defined in the supplied {@code annotationType} that is not aliased or * does not have a default value. * @param attributes the map of annotation attributes; never {@code null} * @param annotationType the type of annotation to synthesize; never {@code null} * @param annotatedElement the element that is annotated with the annotation * of the supplied type; may be {@code null} if unknown */ MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType, @Nullable AnnotatedElement annotatedElement) { super(annotationType, annotatedElement, enrichAndValidateAttributes(attributes, annotationType)); }
@SuppressWarnings("unchecked") private void assertEnrichAndValidateAttributes(Map<String, Object> sourceAttributes, Map<String, Object> expected) throws Exception { Class<? extends Annotation> annotationType = ImplicitAliasesContextConfig.class; // Since the ordering of attribute methods returned by the JVM is non-deterministic, // we have to rig the attributeAliasesCache in AnnotationUtils so that the tests // consistently fail in case enrichAndValidateAttributes() is buggy. // Otherwise, these tests would intermittently pass even for an invalid implementation. Field cacheField = AnnotationUtils.class.getDeclaredField("attributeAliasesCache"); cacheField.setAccessible(true); Map<Class<? extends Annotation>, MultiValueMap<String, String>> attributeAliasesCache = (Map<Class<? extends Annotation>, MultiValueMap<String, String>>) cacheField.get(null); // Declare aliases in an order that will cause enrichAndValidateAttributes() to // fail unless it considers all aliases in the set of implicit aliases. MultiValueMap<String, String> aliases = new LinkedMultiValueMap<>(); aliases.put("xmlFile", Arrays.asList("value", "groovyScript", "location1", "location2", "location3")); aliases.put("groovyScript", Arrays.asList("value", "xmlFile", "location1", "location2", "location3")); aliases.put("value", Arrays.asList("xmlFile", "groovyScript", "location1", "location2", "location3")); aliases.put("location1", Arrays.asList("xmlFile", "groovyScript", "value", "location2", "location3")); aliases.put("location2", Arrays.asList("xmlFile", "groovyScript", "value", "location1", "location3")); aliases.put("location3", Arrays.asList("xmlFile", "groovyScript", "value", "location1", "location2")); attributeAliasesCache.put(annotationType, aliases); MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(sourceAttributes, annotationType, null); Map<String, Object> enriched = extractor.getSource(); assertEquals("attribute map size", expected.size(), enriched.size()); expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue))); }
@Override @Nullable protected Object getRawAttributeValue(Method attributeMethod) { return getRawAttributeValue(attributeMethod.getName()); }
@Test public void enrichAndValidateAttributesWithSingleElementThatOverridesAnArray() { Map<String, Object> attributes = new HashMap<String, Object>() {{ // Intentionally storing 'value' as a single String instead of an array. // put("value", asArray("/foo")); put("value", "/foo"); put("name", "test"); }}; Map<String, Object> expected = new HashMap<String, Object>() {{ put("value", asArray("/foo")); put("path", asArray("/foo")); put("name", "test"); put("method", new RequestMethod[0]); }}; MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(attributes, WebMapping.class, null); Map<String, Object> enriched = extractor.getSource(); assertEquals("attribute map size", expected.size(), enriched.size()); expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue))); }
@Override @Nullable protected Object getRawAttributeValue(Method attributeMethod) { return getRawAttributeValue(attributeMethod.getName()); }
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?
@Override @Nullable protected Object getRawAttributeValue(String attributeName) { return getSource().get(attributeName); }
@Override @Nullable protected Object getRawAttributeValue(Method attributeMethod) { return getRawAttributeValue(attributeMethod.getName()); }
/** * Construct a new {@code MapAnnotationAttributeExtractor}. * <p>The supplied map must contain a key-value pair for every attribute * defined in the supplied {@code annotationType} that is not aliased or * does not have a default value. * @param attributes the map of annotation attributes; never {@code null} * @param annotationType the type of annotation to synthesize; never {@code null} * @param annotatedElement the element that is annotated with the annotation * of the supplied type; may be {@code null} if unknown */ MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType, @Nullable AnnotatedElement annotatedElement) { super(annotationType, annotatedElement, enrichAndValidateAttributes(attributes, annotationType)); }
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?
@Override @Nullable protected Object getRawAttributeValue(String attributeName) { return getSource().get(attributeName); }
@Override @Nullable protected Object getRawAttributeValue(Method attributeMethod) { return getRawAttributeValue(attributeMethod.getName()); }
/** * Construct a new {@code MapAnnotationAttributeExtractor}. * <p>The supplied map must contain a key-value pair for every attribute * defined in the supplied {@code annotationType} that is not aliased or * does not have a default value. * @param attributes the map of annotation attributes; never {@code null} * @param annotationType the type of annotation to synthesize; never {@code null} * @param annotatedElement the element that is annotated with the annotation * of the supplied type; may be {@code null} if unknown */ MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType, @Nullable AnnotatedElement annotatedElement) { super(annotationType, annotatedElement, enrichAndValidateAttributes(attributes, annotationType)); }
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?
@Override @Nullable protected Object getRawAttributeValue(String attributeName) { return getSource().get(attributeName); }
@Override @Nullable protected Object getRawAttributeValue(Method attributeMethod) { return getRawAttributeValue(attributeMethod.getName()); }
/** * Construct a new {@code MapAnnotationAttributeExtractor}. * <p>The supplied map must contain a key-value pair for every attribute * defined in the supplied {@code annotationType} that is not aliased or * does not have a default value. * @param attributes the map of annotation attributes; never {@code null} * @param annotationType the type of annotation to synthesize; never {@code null} * @param annotatedElement the element that is annotated with the annotation * of the supplied type; may be {@code null} if unknown */ MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType, @Nullable AnnotatedElement annotatedElement) { super(annotationType, annotatedElement, enrichAndValidateAttributes(attributes, annotationType)); }
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?