如果您希望每次注入减少到一行,您可以添加注释和条件转换器。这还将在 IntelliJ 中保留 ctrl-click 导航和自动完成功能。
@SpringBootApplication
public class DemoApplication {
@Value("classpath:application.properties")
@FromResource
String someFileContents;
@PostConstruct
void init() {
if (someFileContents.startsWith("classpath:"))
throw new RuntimeException("injection failed");
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
DemoApplication(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
// doing it in constructor ensures it executes before @Value injection in application
// if you don't inject values into application class, you can extract that to separate configuration
environment.getConversionService().addConverter(new ConditionalGenericConverter() {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return targetType.hasAnnotation(FromResource.class);
}
@Override
public Set<GenericConverter.ConvertiblePair> getConvertibleTypes() {
return Set.of(new GenericConverter.ConvertiblePair(String.class, String.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
try (final var stream = resourceLoader.getResource(Objects.toString(source)).getInputStream()) {
return StreamUtils.copyToString(stream, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
});
}
}
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FromResource {
}