Spring custom converter gets overwritten

Viewed 915

This is my first post, so please excuse me if I miss to follow any convention of posting a good question.

I am coding a RESTful service using Spring REST. The signature of the service is as below.

@RestController
@RequestMapping(value = "/{param1}/{param2}/myservice", produces = MediaType.APPLICATION_JSON_VALUE)
public class MyService {

    @RequestMapping(value = "/{param3}", method = GET)
    public MyResponseObj getMyResponseDetails(MyRequestObject request){
        //Service logic code
    }
}

In above example, MyRequestObject contains a custom date object with a specific format. For the reference of this question, the name of the custom date object of MyDate in MyRequestObject is myDate.

My objective here is to convert the string value of myDate coming as a query parameter with name myDate. I have purposefully kept the query parameter name the same as of the inner object name within MyRequestObject class, so that Spring can implicitly assign the value to the myDate attribute of the MyRequestObject instance of the method argument. To make this auto assignment, I ensured to keep a constructor for MyDate with a String parameter. But, Spring does not do this auto-assignment for myDate value.

So, after reading several posts on this forum, I created a custom converter to convert a String object to MyDate object. Below is my code for the same.

@Component
public class StringToMyDateConverter implements Converter<String, MyDate> {
    public MyDate convert(String s){
        //MyDate.parseData(String) is a custom method to convert a String to MyDate object
        return MyDate.parseData(s);
    }
}

Then, I had added below configuration into my Spring config.xml file to add this custom converter class into Spring's default conversion service.

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.my.service.rest.util.conversion.StringToMyDateConverter"/>
        </set>
    </property>
</bean>

During application startup while debug, I have found that my custom converter code is getting executed and the Spring's default converter service registers my custom converter. However, I have also noticed that the Spring's internal code to initialize FormattingConversionServiceFactoryBean is getting executed multiple times during start up of the service. And that eventually resulted into overwriting of the converter service listing, which did not have my custom converter that got registered before.

So, when I invoke the REST service URL mentioned below, I get below mentioned error.

URL http://localhost:7880/project/json/value1/value2/myservice/value3?myDate=2017-09-12

Exception

org.springframework.validation.BindException: 
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'request' on field 'myDate': rejected value [2017-09-12]; codes [typeMismatch.request.myDate,typeMismatch.myDate,typeMismatch.com.my.service.xml.datatype.MyDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [request.myDate,myDate]; arguments []; default message [myDate]]; default message [Failed to convert property value of type [java.lang.String] to required type [com.my.service.xml.datatype.MyDate] for property 'myDate'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.my.service.xml.datatype.MyDate] for property 'myDate': no matching editors or conversion strategy found]

It is important to mention here that my project has a complex module structure having multiple Spring configurations.

I think, because of that Spring is initializing the default conversion service multiple times. Though, I am not able to determine the order of configuration invocations so that I can prevent Spring overwriting my customer configuration added in the list. I have also tried the annotation based configuration class as listed below to achieve this result. But that also resulted in same issue.

@Configuration
public class ConversionServiceProvider {
    @Autowired
    private StringToMyDateConverter stringToMyDateConverter;

    @Bean
    public ConversionService getConversionService() {
        ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
        bean.setConverters(getConverters());
        bean.afterPropertiesSet();
        ConversionService object = bean.getObject();
        return object;
    }

    private Set<Converter<?, ?>> getConverters() {
        Set<Converter<?, ?>> converters = new HashSet<>();

        converters.add(stringToMyDateConverter);
        // add here more custom converters, either as spring bean references or directly instantiated

        return converters;
    }
}

Can you please suggest me anything that I can try here to solve this issue? Please excuse me for the lengthy question, but I think that would help to understand the situation and problem better.

Thanks!!

0 Answers
Related