org.springframework.aot.hint.ResourceHints Maven / Gradle / Ivy
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aot.hint;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
/**
* Gather the need for resources available at runtime.
*
* @author Stephane Nicoll
* @author Sam Brannen
* @since 6.0
*/
public class ResourceHints {
private final Set types;
private final List resourcePatternHints;
private final Set resourceBundleHints;
public ResourceHints() {
this.types = new HashSet<>();
this.resourcePatternHints = new ArrayList<>();
this.resourceBundleHints = new LinkedHashSet<>();
}
/**
* Return the resources that should be made available at runtime.
* @return a stream of {@link ResourcePatternHints}
*/
public Stream resourcePatternHints() {
Stream patterns = this.resourcePatternHints.stream();
return (this.types.isEmpty() ? patterns
: Stream.concat(Stream.of(typesPatternResourceHint()), patterns));
}
/**
* Return the resource bundles that should be made available at runtime.
* @return a stream of {@link ResourceBundleHint}
*/
public Stream resourceBundleHints() {
return this.resourceBundleHints.stream();
}
/**
* Register a pattern if the given {@code location} is available on the
* classpath. This delegates to {@link ClassLoader#getResource(String)}
* which validates directories as well. The location is not included in
* the hint.
* @param classLoader the classloader to use
* @param location a '/'-separated path name that should exist
* @param resourceHint a builder to customize the resource pattern
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerPatternIfPresent(@Nullable ClassLoader classLoader, String location,
Consumer resourceHint) {
ClassLoader classLoaderToUse = (classLoader != null) ? classLoader : getClass().getClassLoader();
if (classLoaderToUse.getResource(location) != null) {
registerPattern(resourceHint);
}
return this;
}
/**
* Register that the resources matching the specified pattern should be
* made available at runtime.
* @param resourceHint a builder to further customize the resource pattern
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerPattern(@Nullable Consumer resourceHint) {
ResourcePatternHints.Builder builder = new ResourcePatternHints.Builder();
if (resourceHint != null) {
resourceHint.accept(builder);
}
this.resourcePatternHints.add(builder.build());
return this;
}
/**
* Register that the resources matching the specified pattern should be
* made available at runtime.
* @param include a pattern of the resources to include (see {@link ResourcePatternHint} documentation)
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerPattern(String include) {
return registerPattern(builder -> builder.includes(include));
}
/**
* Register that the supplied resource should be made available at runtime.
* @param resource the resource to register
* @throws IllegalArgumentException if the supplied resource is not a
* {@link ClassPathResource} or does not {@linkplain Resource#exists() exist}
* @see #registerPattern(String)
* @see ClassPathResource#getPath()
*/
public void registerResource(Resource resource) {
if (resource instanceof ClassPathResource classPathResource && classPathResource.exists()) {
registerPattern(classPathResource.getPath());
}
else {
throw new IllegalArgumentException("Resource must be a ClassPathResource that exists: " + resource);
}
}
/**
* Register that the bytecode of the type defined by the specified
* {@link TypeReference} should be made available at runtime.
* @param type the type to include
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerType(TypeReference type) {
this.types.add(type);
return this;
}
/**
* Register that the bytecode of the specified type should be made
* available at runtime.
* @param type the type to include
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerType(Class type) {
return registerType(TypeReference.of(type));
}
/**
* Register that the resource bundle with the specified base name should
* be made available at runtime.
* @param baseName the base name of the resource bundle
* @param resourceHint a builder to further customize the resource bundle
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerResourceBundle(String baseName, @Nullable Consumer resourceHint) {
ResourceBundleHint.Builder builder = new ResourceBundleHint.Builder(baseName);
if (resourceHint != null) {
resourceHint.accept(builder);
}
this.resourceBundleHints.add(builder.build());
return this;
}
/**
* Register that the resource bundle with the specified base name should
* be made available at runtime.
* @param baseName the base name of the resource bundle
* @return {@code this}, to facilitate method chaining
*/
public ResourceHints registerResourceBundle(String baseName) {
return registerResourceBundle(baseName, null);
}
private ResourcePatternHints typesPatternResourceHint() {
ResourcePatternHints.Builder builder = new ResourcePatternHints.Builder();
this.types.forEach(type -> builder.includes(toIncludePattern(type)));
return builder.build();
}
private String toIncludePattern(TypeReference type) {
return type.getName().replace(".", "/") + ".class";
}
}