Search code examples
javaspringspring-bootspring-annotations

How to migrate Spring Config XML to Spring Boot annotations


I am using Spring boot to create an application for XML marshalling. I followed some tutorials to start the application. I want to avoid any Spring config using xml binding file and want to use annotations instead.

I'm not sure how to migrate this configuration file into annotation driven application.

 <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="XMLConverter" class="com.java2s.common.XMLConverter">
    <property name="marshaller" ref="castorMarshaller" />
    <property name="unmarshaller" ref="castorMarshaller" />
  </bean>
  <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
</beans>

At the moment I have written this code:

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
@Configuration
public class Application implements CommandLineRunner{

    private static final String XML_FILE_NAME = "whitelist.xml";

    @Autowired
    XMLConverter converter;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... arg0) throws Exception {
        Whitelist whitelist = new Whitelist("example");
        converter.convertFromObjectToXML(whitelist, XML_FILE_NAME);
    }
}

And this:

import javax.xml.transform.stream.StreamResult;

import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.Marshaller;

@Configuration
public class XMLConverter {


    private Marshaller marshaller;

    public Marshaller getMarshaller() {
        return marshaller;
    }

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void convertFromObjectToXML(Object object, String filepath) throws IOException{

        FileOutputStream fileOutputStream = null;
        try{
            fileOutputStream = new FileOutputStream(filepath);
            getMarshaller().marshal(object, new StreamResult(fileOutputStream));
        }finally {
            if(fileOutputStream != null) {
                fileOutputStream.close();
            }
        }
    }
}

I get a Nullpointer at getMarshaller().marshal(object, new StreamResult(fileOutputStream)); because marshaller is null.

In the config file there is the reference to the CastorMarshaller class and to the marshaller property.

How can I migrate this in to an annotation driven application?

Thanks for your help.

EDIT1:

<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
    <property name="mappingLocation" value="classpath:mapping.xml" />
</bean>

Solution

  • First off: The @Configuration annotation should be used for on the class that defines the Java Configuration of you application context which is normally a separate file. Instead annotate your classes with @Component:

    @SpringBootApplication
    @EnableAutoConfiguration
    @ComponentScan
    @Component
    public class Application implements CommandLineRunner{
    ...
    

    In addition in your XML convertor class the marshaller must be annotated, so it can be wired with the bean definition: @Configuration

    public class XMLConverter {
    
        @Autowired
        private Marshaller marshaller;
    ...
    

    And finally you need an application context class:

    @Configuration
    public class ApplicationContext {
        @Bean
        public CastorMarshaller castorMarshaller() {
            return new CastorMarshaller();
        }
    
        @Bean
        public XMLConverter XMLConverter() {
            XMLConverter convertor = new XMLConverter();
            CastorMarshaller marshaller = castorMarshaller();
            convertor.setMarshaller(marshaller);
            convertor.setUnmarshaller(marshaller);
        }
    }
    

    And change the code in your application main method to:

    SpringApplication.run(ApplicationContext .class, args);
    

    EDIT: CastorMarhsaller with mappingLocation

       @Bean
        public CastorMarshaller castorMarshaller() {
            ClassPathContextResource resource = new ClassPathContextResource("mapping.xml", getClass().getClassLoader());
            CastorMarshaller marshaller = new CastorMarshaller();
            marshaller.setMappingLocation(resource);
            return marshaller;
        }
    

    If the same resource is also used elsewhere you can define it as bean instead and reuse it, in a similar fashion as shown above.