private void processNestedType(String prefix, TypeElement element, String name, ExecutableElement getter, VariableElement field, TypeMirror returnType) { Element returnElement = this.processingEnv.getTypeUtils().asElement(returnType); boolean isNested = isNested(returnElement, field, element); AnnotationMirror annotation = getAnnotation(getter, configurationPropertiesAnnotation()); if (returnElement != null && returnElement instanceof TypeElement && annotation == null && isNested) { String nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, name); this.metadataCollector.add(ItemMetadata.newGroup(nestedPrefix, this.typeUtils.getType(returnElement), this.typeUtils.getType(element), (getter == null ? null : getter.toString()))); processTypeElement(nestedPrefix, (TypeElement) returnElement); } }
@Test public void simpleProperties() throws Exception { ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata) .has(Metadata.withGroup("simple").fromSource(SimpleProperties.class)); assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) .fromSource(SimpleProperties.class) .withDescription("The name of this simple properties.") .withDefaultValue("boot").withDeprecation(null, null)); assertThat(metadata).has(Metadata.withProperty("simple.flag", Boolean.class) .fromSource(SimpleProperties.class).withDescription("A simple flag.") .withDeprecation(null, null)); assertThat(metadata).has(Metadata.withProperty("simple.comparator")); assertThat(metadata).doesNotHave(Metadata.withProperty("simple.counter")); assertThat(metadata).doesNotHave(Metadata.withProperty("simple.size")); }
@Test public void parseCollectionConfig() throws Exception { ConfigurationMetadata metadata = compile(SimpleCollectionProperties.class); // getter and setter assertThat(metadata).has(Metadata.withProperty("collection.integers-to-names", "java.util.Map<java.lang.Integer,java.lang.String>")); assertThat(metadata).has(Metadata.withProperty("collection.longs", "java.util.Collection<java.lang.Long>")); assertThat(metadata).has(Metadata.withProperty("collection.floats", "java.util.List<java.lang.Float>")); // getter only assertThat(metadata).has(Metadata.withProperty("collection.names-to-integers", "java.util.Map<java.lang.String,java.lang.Integer>")); assertThat(metadata).has(Metadata.withProperty("collection.bytes", "java.util.Collection<java.lang.Byte>")); assertThat(metadata).has(Metadata.withProperty("collection.doubles", "java.util.List<java.lang.Double>")); }
@Test public void innerClassProperties() throws Exception { ConfigurationMetadata metadata = compile(InnerClassProperties.class); assertThat(metadata) .has(Metadata.withGroup("config").fromSource(InnerClassProperties.class)); assertThat(metadata).has( Metadata.withGroup("config.first").ofType(InnerClassProperties.Foo.class) .fromSource(InnerClassProperties.class)); assertThat(metadata).has(Metadata.withProperty("config.first.name")); assertThat(metadata).has(Metadata.withProperty("config.first.bar.name")); assertThat(metadata).has( Metadata.withGroup("config.the-second", InnerClassProperties.Foo.class) .fromSource(InnerClassProperties.class)); assertThat(metadata).has(Metadata.withProperty("config.the-second.name")); assertThat(metadata).has(Metadata.withProperty("config.the-second.bar.name")); assertThat(metadata).has(Metadata.withGroup("config.third") .ofType(SimplePojo.class).fromSource(InnerClassProperties.class)); assertThat(metadata).has(Metadata.withProperty("config.third.value")); assertThat(metadata).has(Metadata.withProperty("config.fourth")); assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth")); }
@Test public void mergingOfHintWithProvider() throws Exception { writeAdditionalHints(new ItemHint("simple.theName", Collections.<ItemHint.ValueHint>emptyList(), Arrays.asList( new ItemHint.ValueProvider("first", Collections.<String, Object>singletonMap("target", "org.foo")), new ItemHint.ValueProvider("second", null)))); ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) .fromSource(SimpleProperties.class) .withDescription("The name of this simple properties.") .withDefaultValue("boot").withDeprecation(null, null)); assertThat(metadata).has(Metadata.withHint("simple.the-name") .withProvider("first", "target", "org.foo").withProvider("second")); }
@Override protected ConfigurationMetadata writeMetaData() { super.writeMetaData(); try { File metadataFile = new File(this.outputLocation, "META-INF/spring-configuration-metadata.json"); if (metadataFile.isFile()) { this.metadata = new JsonMarshaller() .read(new FileInputStream(metadataFile)); } else { this.metadata = new ConfigurationMetadata(); } return this.metadata; } catch (IOException e) { throw new RuntimeException("Failed to read metadata from disk", e); } }
@Test public void mergingOfAdditionalMetadata() throws Exception { File metaInfFolder = new File(this.compiler.getOutputLocation(), "META-INF"); metaInfFolder.mkdirs(); File additionalMetadataFile = new File(metaInfFolder, "additional-spring-configuration-metadata.json"); additionalMetadataFile.createNewFile(); JSONObject property = new JSONObject(); property.put("name", "foo"); property.put("type", "java.lang.String"); property.put("sourceType", AdditionalMetadata.class.getName()); JSONArray properties = new JSONArray(); properties.put(property); JSONObject additionalMetadata = new JSONObject(); additionalMetadata.put("properties", properties); FileWriter writer = new FileWriter(additionalMetadataFile); additionalMetadata.write(writer); writer.flush(); ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata).has(Metadata.withProperty("simple.comparator")); assertThat(metadata).has(Metadata.withProperty("foo", String.class) .fromSource(AdditionalMetadata.class)); }
@Test public void incrementalBuildTypeRenamed() throws Exception { TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, BarProperties.class); ConfigurationMetadata metadata = project.fullBuild(); assertThat(metadata).has( Metadata.withProperty("foo.counter").fromSource(FooProperties.class)); assertThat(metadata).has( Metadata.withProperty("bar.counter").fromSource(BarProperties.class)); assertThat(metadata).doesNotHave(Metadata.withProperty("bar.counter") .fromSource(RenamedBarProperties.class)); project.delete(BarProperties.class); project.add(RenamedBarProperties.class); metadata = project.incrementalBuild(RenamedBarProperties.class); assertThat(metadata).has( Metadata.withProperty("foo.counter").fromSource(FooProperties.class)); assertThat(metadata).doesNotHave( Metadata.withProperty("bar.counter").fromSource(BarProperties.class)); assertThat(metadata).has(Metadata.withProperty("bar.counter") .fromSource(RenamedBarProperties.class)); }
public ConfigurationMetadata readMetadata() { try { return readMetadata(getMetadataResource().openInputStream()); } catch (IOException ex) { return null; } }
public void writeMetadata(ConfigurationMetadata metadata) throws IOException { if (!metadata.getItems().isEmpty()) { OutputStream outputStream = createMetadataResource().openOutputStream(); try { new JsonMarshaller().write(metadata, outputStream); } finally { outputStream.close(); } } }
protected ConfigurationMetadata writeMetaData() { ConfigurationMetadata metadata = this.metadataCollector.getMetadata(); metadata = mergeAdditionalMetadata(metadata); if (!metadata.getItems().isEmpty()) { try { this.metadataStore.writeMetadata(metadata); } catch (IOException ex) { throw new IllegalStateException("Failed to write metadata", ex); } return metadata; } return null; }
/** * Creates a new {@code MetadataProcessor} instance. * @param processingEnvironment The processing environment of the build * @param previousMetadata Any previous metadata or {@code null} */ public MetadataCollector(ProcessingEnvironment processingEnvironment, ConfigurationMetadata previousMetadata) { this.processingEnvironment = processingEnvironment; this.previousMetadata = previousMetadata; this.typeUtils = new TypeUtils(processingEnvironment); }
@Override public boolean matches(ConfigurationMetadata value) { ItemMetadata itemMetadata = getFirstItemWithName(value, this.name); if (itemMetadata == null) { return false; } if (this.type != null && !this.type.equals(itemMetadata.getType())) { return false; } if (this.sourceType != null && !this.sourceType.getName().equals(itemMetadata.getSourceType())) { return false; } if (this.defaultValue != null && !ObjectUtils .nullSafeEquals(this.defaultValue, itemMetadata.getDefaultValue())) { return false; } if (this.description != null && !this.description.equals(itemMetadata.getDescription())) { return false; } if (this.deprecation == null && itemMetadata.getDeprecation() != null) { return false; } if (this.deprecation != null && !this.deprecation.equals(itemMetadata.getDeprecation())) { return false; } return true; }
private ItemMetadata getFirstItemWithName(ConfigurationMetadata metadata, String name) { for (ItemMetadata item : metadata.getItems()) { if (item.isOfItemType(this.itemType) && name.equals(item.getName())) { return item; } } return null; }
@Override public boolean matches(ConfigurationMetadata metadata) { ItemHint itemHint = getFirstHintWithName(metadata, this.name); if (itemHint == null) { return false; } return matches(itemHint, this.valueConditions) && matches(itemHint, this.providerConditions); }
private ItemHint getFirstHintWithName(ConfigurationMetadata metadata, String name) { for (ItemHint hint : metadata.getHints()) { if (name.equals(hint.getName())) { return hint; } } return null; }
@Test public void simplePrefixValueProperties() throws Exception { ConfigurationMetadata metadata = compile(SimplePrefixValueProperties.class); assertThat(metadata).has(Metadata.withGroup("simple") .fromSource(SimplePrefixValueProperties.class)); assertThat(metadata).has(Metadata.withProperty("simple.name", String.class) .fromSource(SimplePrefixValueProperties.class)); }
@Test public void hierarchicalProperties() throws Exception { ConfigurationMetadata metadata = compile(HierarchicalProperties.class); assertThat(metadata).has(Metadata.withGroup("hierarchical") .fromSource(HierarchicalProperties.class)); assertThat(metadata).has(Metadata.withProperty("hierarchical.first", String.class) .fromSource(HierarchicalProperties.class)); assertThat(metadata) .has(Metadata.withProperty("hierarchical.second", String.class) .fromSource(HierarchicalProperties.class)); assertThat(metadata).has(Metadata.withProperty("hierarchical.third", String.class) .fromSource(HierarchicalProperties.class)); }
@Test @SuppressWarnings("deprecation") public void deprecatedProperties() throws Exception { Class<?> type = org.springframework.boot.configurationsample.simple.DeprecatedProperties.class; ConfigurationMetadata metadata = compile(type); assertThat(metadata).has(Metadata.withGroup("deprecated").fromSource(type)); assertThat(metadata).has(Metadata.withProperty("deprecated.name", String.class) .fromSource(type).withDeprecation(null, null)); assertThat(metadata) .has(Metadata.withProperty("deprecated.description", String.class) .fromSource(type).withDeprecation(null, null)); }
@Test public void singleDeprecatedProperty() throws Exception { Class<?> type = DeprecatedSingleProperty.class; ConfigurationMetadata metadata = compile(type); assertThat(metadata).has(Metadata.withGroup("singledeprecated").fromSource(type)); assertThat(metadata) .has(Metadata.withProperty("singledeprecated.new-name", String.class) .fromSource(type)); assertThat(metadata).has(Metadata .withProperty("singledeprecated.name", String.class).fromSource(type) .withDeprecation("renamed", "singledeprecated.new-name")); }
@Test public void deprecatedOnUnrelatedSetter() throws Exception { Class<?> type = DeprecatedUnrelatedMethodPojo.class; ConfigurationMetadata metadata = compile(type); assertThat(metadata).has(Metadata.withGroup("not.deprecated").fromSource(type)); assertThat(metadata) .has(Metadata.withProperty("not.deprecated.counter", Integer.class) .withNoDeprecation().fromSource(type)); assertThat(metadata) .has(Metadata.withProperty("not.deprecated.flag", Boolean.class) .withNoDeprecation().fromSource(type)); }
@Test public void boxingOnSetter() throws IOException { Class<?> type = BoxingPojo.class; ConfigurationMetadata metadata = compile(type); assertThat(metadata).has(Metadata.withGroup("boxing").fromSource(type)); assertThat(metadata).has( Metadata.withProperty("boxing.flag", Boolean.class).fromSource(type)); assertThat(metadata).has( Metadata.withProperty("boxing.counter", Integer.class).fromSource(type)); }
@Test public void simpleMethodConfig() throws Exception { ConfigurationMetadata metadata = compile(SimpleMethodConfig.class); assertThat(metadata) .has(Metadata.withGroup("foo").fromSource(SimpleMethodConfig.class)); assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) .fromSource(SimpleMethodConfig.Foo.class)); assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) .fromSource(SimpleMethodConfig.Foo.class)); }
@Test public void invalidMethodConfig() throws Exception { ConfigurationMetadata metadata = compile(InvalidMethodConfig.class); assertThat(metadata).has(Metadata.withProperty("something.name", String.class) .fromSource(InvalidMethodConfig.class)); assertThat(metadata).isNotEqualTo(Metadata.withProperty("invalid.name")); }
@Test public void methodAndClassConfig() throws Exception { ConfigurationMetadata metadata = compile(MethodAndClassConfig.class); assertThat(metadata).has(Metadata.withProperty("conflict.name", String.class) .fromSource(MethodAndClassConfig.Foo.class)); assertThat(metadata).has(Metadata.withProperty("conflict.flag", Boolean.class) .fromSource(MethodAndClassConfig.Foo.class)); assertThat(metadata).has(Metadata.withProperty("conflict.value", String.class) .fromSource(MethodAndClassConfig.class)); }
@Test public void innerClassAnnotatedGetterConfig() throws Exception { ConfigurationMetadata metadata = compile(InnerClassAnnotatedGetterConfig.class); assertThat(metadata).has(Metadata.withProperty("specific.value")); assertThat(metadata).has(Metadata.withProperty("foo.name")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("specific.foo")); }
@Test public void excludedTypesPojo() throws IOException { ConfigurationMetadata metadata = compile(ExcludedTypesPojo.class); assertThat(metadata).has(Metadata.withProperty("excluded.name")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("excluded.class-loader")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("excluded.data-source")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("excluded.print-writer")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("excluded.writer")); assertThat(metadata).isNotEqualTo(Metadata.withProperty("excluded.writer-array")); }
@Test public void doubleRegistration() throws IOException { ConfigurationMetadata metadata = compile(DoubleRegistrationProperties.class); assertThat(metadata).has(Metadata.withGroup("one")); assertThat(metadata).has(Metadata.withGroup("two")); assertThat(metadata).has(Metadata.withProperty("one.value")); assertThat(metadata).has(Metadata.withProperty("two.value")); assertThat(metadata.getItems()).hasSize(4); }
@Test public void lombokInnerClassProperties() throws Exception { ConfigurationMetadata metadata = compile(LombokInnerClassProperties.class); assertThat(metadata).has(Metadata.withGroup("config") .fromSource(LombokInnerClassProperties.class)); assertThat(metadata).has(Metadata.withGroup("config.first") .ofType(LombokInnerClassProperties.Foo.class) .fromSource(LombokInnerClassProperties.class)); assertThat(metadata).has(Metadata.withProperty("config.first.name")); assertThat(metadata).has(Metadata.withProperty("config.first.bar.name")); assertThat(metadata).has( Metadata.withGroup("config.second", LombokInnerClassProperties.Foo.class) .fromSource(LombokInnerClassProperties.class)); assertThat(metadata).has(Metadata.withProperty("config.second.name")); assertThat(metadata).has(Metadata.withProperty("config.second.bar.name")); assertThat(metadata) .has(Metadata.withGroup("config.third").ofType(SimpleLombokPojo.class) .fromSource(LombokInnerClassProperties.class)); // For some reason the annotation processor resolves a type for SimpleLombokPojo // that is resolved (compiled) and the source annotations are gone. Because we // don't see the @Data annotation anymore, no field is harvested. What is crazy is // that a sample project works fine so this seem to be related to the unit test // environment for some reason. assertThat(metadata, // containsProperty("config.third.value")); assertThat(metadata).has(Metadata.withProperty("config.fourth")); assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth")); }
@Test public void mergingOfAdditionalProperty() throws Exception { ItemMetadata property = ItemMetadata.newProperty(null, "foo", "java.lang.String", AdditionalMetadata.class.getName(), null, null, null, null); writeAdditionalMetadata(property); ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata).has(Metadata.withProperty("simple.comparator")); assertThat(metadata).has(Metadata.withProperty("foo", String.class) .fromSource(AdditionalMetadata.class)); }
@Test public void mergeExistingPropertyDefaultValue() throws Exception { ItemMetadata property = ItemMetadata.newProperty("simple", "flag", null, null, null, null, true, null); writeAdditionalMetadata(property); ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata).has(Metadata.withProperty("simple.flag", Boolean.class) .fromSource(SimpleProperties.class).withDescription("A simple flag.") .withDeprecation(null, null).withDefaultValue(true)); assertThat(metadata.getItems()).hasSize(4); }
@Test public void mergeExistingPropertyDescription() throws Exception { ItemMetadata property = ItemMetadata.newProperty("simple", "comparator", null, null, null, "A nice comparator.", null, null); writeAdditionalMetadata(property); ConfigurationMetadata metadata = compile(SimpleProperties.class); assertThat(metadata) .has(Metadata.withProperty("simple.comparator", "java.util.Comparator<?>") .fromSource(SimpleProperties.class) .withDescription("A nice comparator.")); assertThat(metadata.getItems()).hasSize(4); }