MetadataStore Class — spring-boot Architecture
Architecture documentation for the MetadataStore class in MetadataStore.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataStore.java lines 43–244
class MetadataStore {
static final String METADATA_PATH = "META-INF/spring-configuration-metadata.json";
static final BiFunction<TypeElement, TypeUtils, String> SOURCE_METADATA_PATH = (type,
typeUtils) -> "META-INF/spring/configuration-metadata/%s.json".formatted(typeUtils.getQualifiedName(type));
private static final String ADDITIONAL_METADATA_PATH = "META-INF/additional-spring-configuration-metadata.json";
static final BiFunction<TypeElement, TypeUtils, String> ADDITIONAL_SOURCE_METADATA_PATH = (type,
typeUtils) -> "META-INF/spring/configuration-metadata/additional/%s.json"
.formatted(typeUtils.getQualifiedName(type));
private static final String RESOURCES_DIRECTORY = "resources";
private static final String CLASSES_DIRECTORY = "classes";
private final ProcessingEnvironment environment;
private final TypeUtils typeUtils;
MetadataStore(ProcessingEnvironment environment, TypeUtils typeUtils) {
this.environment = environment;
this.typeUtils = typeUtils;
}
/**
* Read the existing {@link ConfigurationMetadata} of the current module or
* {@code null} if it is not available yet.
* @return the metadata or {@code null} if none is present
*/
ConfigurationMetadata readMetadata() {
return readMetadata(METADATA_PATH);
}
/**
* Read the existing {@link ConfigurationMetadata} for the specified type or
* {@code null} if it is not available yet.
* @param typeElement the type to read metadata for
* @return the metadata for the given type or {@code null}
*/
ConfigurationMetadata readMetadata(TypeElement typeElement) {
return readMetadata(SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils));
}
private ConfigurationMetadata readMetadata(String location) {
try {
return readMetadata(location, getMetadataResource(location).openInputStream());
}
catch (IOException ex) {
return null;
}
}
/**
* Write the module {@link ConfigurationMetadata} to the filesystem.
* @param metadata the metadata to write
* @throws IOException when the write fails
*/
void writeMetadata(ConfigurationMetadata metadata) throws IOException {
writeMetadata(metadata, () -> createMetadataResource(METADATA_PATH));
}
/**
* Write the {@link ConfigurationMetadata} for the {@link TypeElement} to the
* filesystem.
* @param metadata the metadata to write
* @param typeElement the type to write metadata for
* @throws IOException when the write fails
*/
void writeMetadata(ConfigurationMetadata metadata, TypeElement typeElement) throws IOException {
writeMetadata(metadata, () -> createMetadataResource(SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils)));
}
/**
* Write the metadata to the {@link FileObject} provided by the given supplier.
* @param metadata the metadata to provide
* @param fileObjectProvider a supplier for the {@link FileObject} to use
*/
private void writeMetadata(ConfigurationMetadata metadata, FileObjectSupplier fileObjectProvider)
throws IOException {
if (!metadata.getItems().isEmpty()) {
try (OutputStream outputStream = fileObjectProvider.get().openOutputStream()) {
new JsonMarshaller().write(metadata, outputStream);
}
}
}
/**
* Read additional {@link ConfigurationMetadata} for the current module or
* {@code null}.
* @return additional metadata or {@code null} if none is present
*/
ConfigurationMetadata readAdditionalMetadata() {
return readAdditionalMetadata(ADDITIONAL_METADATA_PATH);
}
/**
* Read additional {@link ConfigurationMetadata} for the {@link TypeElement} or
* {@code null}.
* @param typeElement the type to get additional metadata for
* @return additional metadata for the given type or {@code null} if none is present
*/
ConfigurationMetadata readAdditionalMetadata(TypeElement typeElement) {
return readAdditionalMetadata(ADDITIONAL_SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils));
}
private ConfigurationMetadata readAdditionalMetadata(String location) {
try {
InputStream in = getAdditionalMetadataStream(location);
return readMetadata(location, in);
}
catch (IOException ex) {
return null;
}
}
private ConfigurationMetadata readMetadata(String location, InputStream in) {
try (in) {
return new JsonMarshaller().read(in);
}
catch (IOException ex) {
return null;
}
catch (Exception ex) {
throw new InvalidConfigurationMetadataException(
"Invalid additional meta-data in '" + location + "': " + ex.getMessage(), Diagnostic.Kind.ERROR);
}
}
private FileObject getMetadataResource(String location) throws IOException {
return this.environment.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", location);
}
private FileObject createMetadataResource(String location) throws IOException {
return this.environment.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", location);
}
private InputStream getAdditionalMetadataStream(String additionalMetadataLocation) throws IOException {
// Most build systems will have copied the file to the class output location
FileObject fileObject = this.environment.getFiler()
.getResource(StandardLocation.CLASS_OUTPUT, "", additionalMetadataLocation);
InputStream inputStream = getMetadataStream(fileObject);
if (inputStream != null) {
return inputStream;
}
try {
File file = locateAdditionalMetadataFile(new File(fileObject.toUri()), additionalMetadataLocation);
return (file.exists() ? new FileInputStream(file) : fileObject.toUri().toURL().openStream());
}
catch (Exception ex) {
throw new FileNotFoundException();
}
}
private InputStream getMetadataStream(FileObject fileObject) {
try {
return fileObject.openInputStream();
}
catch (IOException ex) {
return null;
}
}
File locateAdditionalMetadataFile(File standardLocation, String additionalMetadataLocation) throws IOException {
if (standardLocation.exists()) {
return standardLocation;
}
String locations = this.environment.getOptions()
.get(ConfigurationMetadataAnnotationProcessor.ADDITIONAL_METADATA_LOCATIONS_OPTION);
if (locations != null) {
for (String location : locations.split(",")) {
File candidate = new File(location, additionalMetadataLocation);
if (candidate.isFile()) {
return candidate;
}
}
}
return new File(locateGradleResourcesDirectory(standardLocation), additionalMetadataLocation);
}
private File locateGradleResourcesDirectory(File standardAdditionalMetadataLocation) throws FileNotFoundException {
String path = standardAdditionalMetadataLocation.getPath();
int index = path.lastIndexOf(CLASSES_DIRECTORY);
if (index < 0) {
throw new FileNotFoundException();
}
String buildDirectoryPath = path.substring(0, index);
File classOutputLocation = standardAdditionalMetadataLocation.getParentFile().getParentFile();
return new File(buildDirectoryPath, RESOURCES_DIRECTORY + '/' + classOutputLocation.getName());
}
/**
* Internal callback that can throw an {@link IOException}.
*/
private interface FileObjectSupplier {
FileObject get() throws IOException;
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free