3

Is there any way to configure Jackson (ConfiguredObjectMapper) which is used for serializing servlet responses?

@Api(name = "rates",
        version = "v1",
        title = "Rates API")
public class RatesApi {
    static Logger LOG = Logger.getLogger(RatesApi.class.getSimpleName());

    @ApiMethod(name = "getLatestRates",
            path = "latest",
            httpMethod = HttpMethod.GET)
    public RatesEnvelope getLatestRates(@Named("base") String base) throws BadRequestException,
            InternalServerErrorException {

        try {
            RatesInfo ratesInfo = DatabaseUtils.getLatestRates(base);
            return new RatesEnvelope(ratesInfo.getDate(), base, ratesInfo.getTimestamp(), ratesInfo.getRates());
        } catch (IllegalArgumentException e) {
            throw new BadRequestException(e.getMessage());
        } catch (com.googlecode.objectify.NotFoundException e) {
            throw new InternalServerErrorException("no available rates");
        }
    }
}

My problem is RatesEnvelope class contains BigDecimal fields which should be configured with mapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN); to avoid E notation.

web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <servlet>
        <servlet-name>CurrencyWebserviceServlet</servlet-name>
        <servlet-class>PACKAGE_NAME.backend.servlet.OpenExchangeRatesWebserviceServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>SystemServiceServlet</servlet-name>
        <servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
        <init-param>
            <param-name>services</param-name>
            <param-value>PACKAGE_NAME.backend.spi.RatesApi</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>CurrencyWebserviceServlet</servlet-name>
        <url-pattern>/cron/fetchlatest</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>SystemServiceServlet</servlet-name>
        <url-pattern>/_ah/spi/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>all</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <filter>
        <filter-name>ObjectifyFilter</filter-name>
        <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ObjectifyFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <!-- Next three lines are for request dispatcher actions -->
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
</web-app>
localhost
  • 5,568
  • 1
  • 33
  • 53

2 Answers2

0

Create an instance of Jackson ObjectMapper. Configure as needed by enabling or disabling features you need. Modify your Spring configuration to use it instead of default one. Java configuration would look something like this:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN);
    converter.setObjectMapper(objectMapper);
    converters.add(converter);
    super.configureMessageConverters(converters);
}
localhost
  • 5,568
  • 1
  • 33
  • 53
VinPro
  • 882
  • 1
  • 6
  • 10
  • Where do i configure Spring? I use Google App Engine and there is nothing related to Spring in my project. – localhost Feb 19 '17 at 17:56
  • In that case you might be using a Guice module like one shown below to create/configure object instances: `public class MyModule implements Module{ @Override public void configure(Binder binder) { //all your object bindings } @Provides ObjectMapper providesObjectMapper(){ ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN); return objectMapper; }` – VinPro Feb 19 '17 at 22:12
  • and what if i don't use Guice? What i would like to know - is there any easy way to configure Jackson? Like editing for config.xml etc. – localhost Feb 20 '17 at 09:13
  • I don't think there will be any just for Jackson. Can you share your web.xml. I suspect you use Google cloud endpoints in which case this post might be helpful http://stackoverflow.com/questions/17128714/appengine-with-google-cloud-endpoints-and-guice – VinPro Feb 20 '17 at 23:30
  • Yep, i use Google Cloud Endpoints. Added web.xml to the question. – localhost Feb 22 '17 at 08:34
0

It looks like you're using Cloud Endpoints Frameworks, which doesn't use Jackson annotations. In your case, you'd use an ApiTransformer to achieve what you want. As an example:

@ApiTransformer(RatesEnvelopeTransformer.class)
public class RatesEnvelope {
    private BigDecimal someBigDecimalField;
    // ...
}

public class RatesEnvelopeTransformer implements Transformer<BigDecimal, String> {
    public String transformTo(BigDecimal in) {
        return in.toPlainString();
    }

    public BigDecimal transformFrom(String in) {
        return new BigDecimal(in);
    }
}
Adam
  • 5,697
  • 1
  • 20
  • 52