0

Migrating from Spring XML configuration style to Spring Java-based configuration (using @Configuration) I run into an issue loading resources, in my case from the classpath.

In XML I did have a bean declared like:

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
  <property name="schema" value="classpath:/xsd/schema.xsd" />
  <property name="contextPath" value="com.company.app.jaxb" />
</bean>

Configuration this bean in a Java class looks like:

@Configuration
public class AppConfig {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setSchema(applicationContext.getResource("classpath:/xsd/schema.xsd"));
        marshaller.setContextPath("com.company.app.jaxb");
        return marshaller;
    }

This will actually throw a NullpointerException during loading of the ApplicationContext because the @Autowired field is not (yet?) autowired...

Q: What is the right solution to load resources (from the classpath and/or in general)? Using the ApplicationContext is promoted in the Spring Documentation: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#context-introduction

Q: And why is the autowired field still null?

Marc vA
  • 51
  • 1
  • 5
  • Usually Spring allows the creation of Java-based configuration via `ApplicationContext context = new AnnotationConfigApplicationContext(springConfig)` where _springConfig_ is the reference to the `@Configuration` annotated configuration class. But I have never used it inside the configuration file itself, TBH. You could also try to initialize the marshaller in a `@PostConstruct` annotated method inside the configuration – Roman Vottner Oct 09 '14 at 15:33
  • I'm starting the `ApplicationContext` from a unit test using the `@RunWith(SpringJUnit4ClassRunner.class)` with `@ContextConfiguration(classes = { AppConfig.class })` ... Is this applying some other lifecycle? – Marc vA Oct 14 '14 at 08:18

2 Answers2

0

For

marshaller.setSchema(applicationContext.getResource("classpath:/xsd/schema.xsd"));

you can instead use

marshaller.setSchema(new ClassPathResource("/xsd/schema.xsd"));

But I am unable to reproduce your injected ApplicationContext field being null.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Hmm.. strange. I get an exception which is inside the beans jar: `java.lang.NoClassDefFoundError: org.springframework.beans.FatalBeanException`. I don't get it at all – Marc vA Oct 14 '14 at 08:22
  • It's a bit hard to put the full stack trace in the comments, @sotirios-delimanolis. I can reproduce this by having two beans inside one `AppConfig` configuration which depend on each other (circular dependency :( ) Yes, I know, I probably should rethink my design here ... ;-) – Marc vA Oct 15 '14 at 06:55
0

So autowiring the ApplicationContext into an @Configuration AppConfig class does work and is actually being autowired. Using it directly in an @Bean method seems to produce a circular autowiring situation. And a StackOverflowError :-(

The solution is to apply a 'post construct pattern' with @PostConstruct ...

Solution in code:

@Configuration
public class AppConfig {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.company.app.jaxb");
        return marshaller;
    }

    @PostConstruct
    public void initMarshaller() {
        marshaller().setSchema(applicationContext.getResource("classpath:/xsd/schema.xsd"));
    }
Marc vA
  • 51
  • 1
  • 5
  • It's great that you found a solution, but absolutely nothing in your question shows anything about a `StackOverflowError`. Also autowiring an `ApplicationContext` in a `@Configuration` class does in, in itself, cause a `StackOverflowError`. There must be something else you are doing that you aren't showing us. – Sotirios Delimanolis Oct 15 '14 at 14:31