Use Spring to inject text file directly to String Use Spring to inject text file directly to String spring spring

Use Spring to inject text file directly to String


Technically you can do this with XML and an awkward combination of factory beans and methods. But why bother when you can use Java configuration?

@Configurationpublic class Spring {    @Value("classpath:choice-test.html")    private Resource sampleHtml;    @Bean    public String sampleHtmlData() {        try(InputStream is = sampleHtml.getInputStream()) {            return IOUtils.toString(is, StandardCharsets.UTF_8);        }    }}

Notice that I also close the stream returned from sampleHtml.getInputStream() by using try-with-resources idiom. Otherwise you'll get memory leak.


There is no built-in functionality for this to my knowledge but you can do it yourself e.g. like this:

<bean id="fileContentHolder">  <property name="content">    <bean class="CustomFileReader" factory-method="readContent">      <property name="filePath" value="path/to/my_file"/>    </bean>   </property></bean>

Where readContent() returns a String which is read from the file on path/to/my_file.


If you want it reduced to one line per injection you can add annotation and conditional converter. This will also preserve ctrl-click navigation and autocomplete in IntelliJ.

@SpringBootApplicationpublic 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 {}