Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

We were using FasterXML on the same object to generate JSON and XML. Unfortunately, the object itself didn’t define the desired markup. It used JAXB annotations to add a wrapper around a set of data.

XML and JSON output based upon class definition

The class had the following property defined:

public List<TestRacingEventResponse> getRacingEvents() { return _racingEvents; }
public void setRacingEvents(List<TestRacingEventResponse> racingEvents) { this._racingEvents = racingEvents; }

This would generate XML like:

<racingEvents>
    <....>
</racingEvents>
<racingEvents>
    <....>
</racingEvents>
<racingEvents>
    <....>
</racingEvents>

The JSON would be outputted like this:

{racingEvents
{…}
}
{racingEvents
{…}
}
{racingEvents
{…}
}

JAXB to create a wrapper and redefine the element

This isn’t what was wanted. The desired output was a racingEvents container around a list of racingEvent containers. This is quite easy in XML via JAXB. The declaration with the required JAXB is as follows:

@XmlElementWrapper(name="racingEvents")
@XmlElement(name="racingEvent")
public List<TestRacingEventResponse> getRacingEvents() { return _racingEvents; }
public void setRacingEvents(List<TestRacingEventResponse> racingEvents) { this._racingEvents = racingEvents; }

This would generate XML like:

<racingEvents>
    <racingEvent>
        <....>
    </racingEvent
    <racingEvent>
        <....>
    </racingEvent
    <racingEvent>
        <....>
    </racingEvent
</racingEvents>

This works great for XML, but JSON doesn’t honor JAXB annotations. This leaves us with two alternatives. Create a class structure that mimics the structures you wanted. That would be creating a RacingEvents property in our enclosing class that is a List, then create a RacingEvent object that has the required fields.

Configure FasterXML (Jackson 2) to honor JAXB Wrapper annotation

Another way to do this is to instruct the JSON marshaller to honor the JAXB annotations. We are using Jackson 2 (FasterXML). In our particular case, we were using CXF for the front-end services. The original XML configuration is as follows:

<jaxrs:server id="hptsWebService" address="/">
    <jaxrs:serviceBeans>
        <bean id="accountServices" class="com.twinspires.hpts.servicedefinitions.AccountServices"/>
        <bean id="racingContentServices" class="com.twinspires.hpts.servicedefinitions.RacingContentServices"/>
        <bean id="systemInfoServices" class="com.twinspires.hpts.servicedefinitions.SystemInfoServices"/>
        <bean id="testerServices" class="com.twinspires.hpts.servicedefinitions.TesterServices"/>
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"/>
    </jaxrs:providers>
</jaxrs:server>

I needed to be able to configure the ObjectMapper. Unfortunately, I couldn’t get to the ObjectMapper in the code because the JacksonJaxbJsonProvider only exposed a MAPPER. That seems like a bug to me. To get around this, I declared the JacksonJaxbJsonProvider separately.

<bean id="jacksonJaxbJsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"/>

<jaxrs:server id="hptsWebService" address="/">
    <jaxrs:serviceBeans>
        <bean id="accountServices" class="com.twinspires.hpts.servicedefinitions.AccountServices"/>
        <bean id="racingContentServices" class="com.twinspires.hpts.servicedefinitions.RacingContentServices"/>
        <bean id="systemInfoServices" class="com.twinspires.hpts.servicedefinitions.SystemInfoServices"/>
        <bean id="testerServices" class="com.twinspires.hpts.servicedefinitions.TesterServices"/>
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <ref bean="jacksonJaxbJsonProvider"/>
    </jaxrs:providers>
</jaxrs:server>

Now that the object is separate, I had to find a place where I could manipulate it. I found an object that was related to the functionality that I needed and added a constructor that took the JacksonJaxbJsonProvider as input. Once I had that object, I could configure to my heart’s content.

My modifications involved creating a new OjbectMapper. I preferred to get the ObjectMapper that was being used, but there was no getter. Once I have the ObjectMapper, I set a property that indicates that I want use the XmlElementWrapper as a wrapper for my output.

    @Autowired
    public HttpUtil(JacksonJaxbJsonProvider jacksonJaxbJsonProvider) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(MapperFeature.-- USE_WRAPPER_NAME_AS_PROPERTY_NAME);
        jacksonJaxbJsonProvider.setMapper(objectMapper);
    }

Now that we have told the JSON marshaller to honor the JAXB wrapper annotation, output should be:

{racingEvents
    {races
        {...}
    }
    {races
        {...}
    }
    {races
        {...}
    }
}

Conclusion

To have a FasterXML honor JAXB annotations when it outputs JSON, you have to instantiate the JacksonJaxbJsonProvider separately so it can be injected. Once it is injected in code, you can create and configure an ObjectMapper.

June 10th, 2016

Posted In: FasterXML, Jackson 2, Java, java ninja, Javaninja, JAXB, json

One Comment

Most of the marshalling I have to do it done by Spring. However, I sometimes have to do this manually. Let’s see how easy it is with Jackson 2 (FasterXML).

Maven dependency

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.3</version>
</dependency>

Import the ObjectMapper

The ObjectMapper is the object that you will instantiate and use for all conversions.

import com.fasterxml.jackson.databind.ObjectMapper;

Object to String

Given an object, it is pretty easy to use an ObjectMapper.

ObjectMapper objectMapper = new ObjectMapper();
String myString = objectMapper.writeValueAsString(myObject);

String to Object

If you have a JSON string and need to convert that to an object, you also use the ObjectMapper.

ObjectMapper objectMapper = new ObjectMapper();
MyObject myObject = objectMapper.readValue(myJsonString, MyObject.class);

May 12th, 2016

Posted In: FasterXML, Java, java ninja, Javaninja, json

Leave a Comment

To use CXF 3.x as your restful interface, use the following dependency.

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxrs</artifactId>
    <version>${cxf.version}</version>
</dependency>

To use CXF 3.x as your rest client, use the following dependency.

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-client</artifactId>
    <version>${cxf.version}</version>
</dependency>

January 13th, 2016

Posted In: CXF, Java, java ninja, Javaninja, json

Tags: , , , ,

Leave a Comment

I was migrating some old Jackson code to Jackson 2 (FasterXML). I ran into where they were telling the Jackson to ignore unknown properties via code.

ObjectMapper mapper = new ObjectMapper();
mapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

The new way to do this in Jackson 2 (FasterXML) is

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

January 13th, 2016

Posted In: Java, java ninja, Javaninja, json, xml

Leave a Comment

We’ve all had this happen. There is a large model that is being converted to JSON, but only a few fields are populated. The result looks something like this

{
    "modelStatus": "ERROR",
    "message": null,
    "messages": [
    ],
    "previousPage": null,
    "nextPage": null,
    "redirect": false,
    "errors": [
    ],
    "errorFields": [
    ],
    "exception": null,
    "ssoToken": null,
    "bossUser": null,
    "idGame": 6067,
    "idAccount": 0,
    "currency": null,
    "language": null,
    "rgsCode": "aristocrat",
    "rgsGameId": "aris50Dragons",
    "tokenType": null,
    "tokenTtl": 0,
    "tokenModelAsJsonString": null,
    "channel": "pc",
    "clientType": "flash",
    "mode": "REAL",
    "clientUrl": "http://***URL with parameters removed***",
    "method": "GET",
    "contentType": null,
    "body": null,
    "status": "ERROR"
}

Jackson 2.0 (e.g. FasterXML) offers an annotation that can be used to tune the behavior of the JSON serializer. This is accomplished by placing a @JsonInclude annotation at the top of the model. There are several options.

NON_NULL can be used to tell FasterXML to not send any elements that are null.

@JsonInclude(JsonInclude.Include.NON_NULL)

This results in the same response appearing like…

{
    "modelStatus": "ERROR",
    "messages": [
    ],
    "redirect": false,
    "errors": [
    ],
    "errorFields": [
    ],
    "idGame": 6067,
    "idAccount": 0,
    "rgsCode": "aristocrat",
    "rgsGameId": "aris50Dragons",
    "tokenTtl": 0,
    "channel": "pc",
    "clientType": "flash",
    "mode": "REAL",
    "clientUrl": "http://***URL with parameters removed***",
    "method": "GET",
    "status": "ERROR"
}

Notice that there are several empty arrays. These can also be removed by specifying that only NON_EMPTY items are sent. To determine if something sould be included in the JSON, several methods are used:

  • null objects are not included
  • Collections and Maps – isEmpty() is called. The item is included if this returns false
  • Arrays – the length must be > than 0 for the array to be included
  • String – the length() is called. The string is included if the value is greater than 0.

This is accomplished by

@JsonInclude(JsonInclude.Include.NON_EMPTY)

August 21st, 2015

Posted In: Java, java ninja, Javaninja, javascript, json

Leave a Comment

The usual usage of a Springframework RestTemplate is to get back an object. Sometimes the object will contain a list. What needs to happen when you need to get back a list of Strings? RestTemplate accepts a parameter that tells it what the data it receives will be put in. I used a String array. It converts the JSON object into a String[] and away I go.

                    String[] pokerTableNames =
                        restTemplate.getForObject(pokerSettingsService.getValueByName(PokerSettings.IGP_ADAPTER_URL) + "/poker/tableNames",
                            String[].class);

February 20th, 2015

Posted In: Java, java ninja, Javaninja, json, Spring

Tags: , , , , , , ,

Leave a Comment

I had used Springframework MVC with JSR-303/349 validations with Spring MVC forms. Those follow the normal pattern that we are all used to. This was my first time writing a RESTful service with Spring MVC that needed to return validation messages. There were a couple of posts on the internet that I used, but none was quite right. This is what I came up with that works.

I have a class that holds a validation message. The ones that I saw on the internet also had a field property. This mimics the way the Spring MVC forms expect the data. It expects a field value and the message value. Since we are writing a service, the field does not provide any connection with the client of the service. This forced us to use custom messages for all of the validations that have the full message that the client would need. Instead of returning “is null”, we returned messages like “Password cannot be null”.

package com.cdi.igs.common.spring.web;

/**
 * Holds a field error.
 * @author norris.shelton
 */
public class FieldError {

    /** The error message for the field. */
    private String message;

    /**
     * Constructor is required to set the object properties.
     * @param message the error message for the field
     */
    public FieldError(String message) {
        this.message = message;
    }

    /** Gets the error message for the field. */
    public String getMessage() {
        return message;
    }
}

The FieldError class was used by the ValidationsMessages class. This was used to create the correct json that we were expecting.

package com.cdi.igs.common.spring.web;

import java.util.ArrayList;
import java.util.List;

/**
 * Contains the controller field validation messages.
 * @author norrisshelton 
 */
public class ValidationMessages {

    /** List of field validation errors. */
    private List<FieldError> fieldErrors = new ArrayList<>();

    /** Gets the list of field validation errors. */
    @SuppressWarnings("UnusedDeclaration")
    public List<FieldError> getFieldErrors() {
        return fieldErrors;
    }

    /** Adds a field validation error. */
    public void addFieldError(String message) {
        FieldError fieldError = new FieldError(message);
        fieldErrors.add(fieldError);
    }
}

The real work is in the exception handler.

  • @ControllerAdvice – this is a new annotation in Spring 3.2. This annotation indicates that this class assists a controller.
  • @ExceptionHandler – indicates that the method handles exceptions of the specified type. MethodArgumentNotValidException exceptions are thrown by validated controller methods that do not handle their validation errors.
  • @ResponseStatus – sets the HTTP status code to be returned for this method once the exception has been handled. In this case, we are returning an HTTP 400 Bad Request.
  • @ResponseBody – indicates that the return object should be bound to the response. In this case, the object will be converted to JSON and returned to the client.
  • package com.cdi.igs.common.spring.web;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.MessageSource;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.http.HttpStatus;
    import org.springframework.validation.BindingResult;
    import org.springframework.validation.FieldError;
    import org.springframework.validation.ObjectError;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    import java.util.Locale;
    
    
    /**
     * Global Spring MVC controller exception handler.
     * @author norris.shelton
     */
    @ControllerAdvice
    public class GlobalControllerExceptionHandler {
    
        private MessageSource messageSource;
    
        @Autowired
        public GlobalControllerExceptionHandler(MessageSource messageSource) {
            this.messageSource = messageSource;
        }
    
        /**
         * Handles validation messages for controller methods that don't handle them directly.
         * @param exception the exception that is thrown when validations errors are not handled by the controller method
         * @return an object containing the validation messages
         */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public ValidationMessages handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
            ValidationMessages validationMessages = new ValidationMessages();
            BindingResult result = exception.getBindingResult();
    
            // process the field validations
            for (FieldError fieldError : result.getFieldErrors()) {
                validationMessages.addFieldError(messageSource.getMessage(fieldError, LocaleContextHolder.getLocale()));
            }
    
            // process the global validations
            for (ObjectError globalError : result.getGlobalErrors()) {
                validationMessages.addFieldError(globalError.getDefaultMessage());
            }
    
            return validationMessages;
        }
    
        /**
         * Resolves localized messages.  Not currently used, but here if we switch to message resource files.
         * @param fieldError the field error object
         * @return the localized error message
         */
        private String resolveLocalizedErrorMessage(FieldError fieldError) {
            Locale currentLocale = LocaleContextHolder.getLocale();
            String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);
    
            //If the message was not found, return the most accurate field error code instead.
            //You can remove this check if you prefer to get the default error message.
            if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
                String[] fieldErrorCodes = fieldError.getCodes();
                localizedErrorMessage = fieldErrorCodes[0];
            }
    
            return localizedErrorMessage;
        }
    }
    

    December 30th, 2013

    Posted In: Java, json, Spring

    2 Comments

I have a list in an object. I need to output this list in XML. Normally this would be accomplished by the following:

@XmlElementWrapper(name = "licenseList")
@XmlElement(name = "license")
public List<WatchLicense> getLicenses() {
    return licenses;
}

This produces the following output

<licenseList>
    <license>data</license>
    <license>data</license>
    <license>data</license>
</licenseList>

This is great, until I have the need to add an attribute to licenseList. You can’t add an attribute to a generated wrapper via annotations only. Enter the xml type adapter. There are three pieces. The defined type that is marshallable (LicenseListType), the annotation of the unmarshallable element with the xml type adapter and then the adapter itself (LicenseListAdapter).

First off is the new type. There are several things here. First off, it is a normal wrapper of the type that used to have to be used before @XmlElementWrapper. You used to have to add this to your class directly as a property. I didn’t want to because the names of the elements and their location had meaning to my views. Second is the addition of the getHashCode() method. This is the attribute that I needed to add. It uses the generated hashCode method.

package com.appriss.jxp.watchapi.jaxb;

import com.appriss.jxp.watchapi.WatchLicense;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.springframework.util.AutoPopulatingList;

import javax.xml.bind.annotation.XmlAttribute;

import java.util.List;

/**
 * Wrapper for list of license.  Normally, this would be handled by adding @XmlElementWrapper(name = "licenseList") to
 * the getter.  In this case, we also need to add a hashCode attribute the value and JAXB doesn't support an element
 * wrapper with an attribute.
 * @author nshelton
 */
public class LicenseListType {

    @XmlAttribute(name = "hashCode")
    public int getHashCode() {
        return hashCode();
    }

    private List<WatchLicense> license = new AutoPopulatingList<WatchLicense>(WatchLicense.class);

    public List<WatchLicense> getLicense() {
        return license;
    }

    public void setLicense(List<WatchLicense> license) {
        this.license = license;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(license).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof LicenseListType) {
            final LicenseListType other = (LicenseListType) obj;
            return new EqualsBuilder().append(license, other.license).isEquals();
        } else {
            return false;
        }
    }
}

Next up is the adapter class which will directly use this new type. The adapter’s job is to translate from one unmarshallable object to a marshallable object.

package com.appriss.jxp.watchapi.jaxb;

import com.appriss.jxp.watchapi.WatchLicense;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import java.util.LinkedList;
import java.util.List;

/**
 * License list type adapter to convert between a list of watch licenses and a license list type.  This would normally
 * be handled by @XmlElementWrapper, but we also need to specify an attribute and JAXB doesn't support attributes on an
 * annotation generated wrapper.
 * @author nshelton
 */
public class LicenseListAdapter extends XmlAdapter<LicenseListType, List<WatchLicense>> {

    /**
     * Convert a value type to a bound type.
     * @param licenseListType The value to be converted. Can be null.
     * @throws Exception if there's an error during the conversion. The caller is responsible for reporting the error to
     *                   the user through {@link javax.xml.bind.ValidationEventHandler}.
     */
    @Override
    public List<WatchLicense> unmarshal(LicenseListType licenseListType) throws Exception {
        List<WatchLicense> watchLicenses = new LinkedList<WatchLicense>();
        watchLicenses.addAll(licenseListType.getLicense());
        return watchLicenses;
    }

    /**
     * Convert a bound type to a value type.
     * @param watchLicenses The value to be converted. Can be null.
     * @throws Exception if there's an error during the conversion. The caller is responsible for reporting the error to
     *                   the user through {@link javax.xml.bind.ValidationEventHandler}.
     */
    @Override
    public LicenseListType marshal(List<WatchLicense> watchLicenses) throws Exception {
        LicenseListType licenseListType = new LicenseListType();
        licenseListType.setLicense(watchLicenses);
        return licenseListType;
    }
}

The magic happens in the marshall and unmarshall methods. In the marshall method, it accepts the unmarshallable class and returns a marshallable class. In the unmarshaller, it accepts the marshallable class and returns the unmarshallable class.

Now all that is left to do is to define the adapter class for a property. The @XmlJavaTypeAdapter annotation is used to identify the class that will be used to marshall/unmarshall this element.

@XmlJavaTypeAdapter(LicenseListAdapter.class)
public List<WatchLicense> getLicenses() {
    return licenses;
}

August 22nd, 2012

Posted In: Java, JAXB, json

Tags: , , ,

2 Comments

Springframework 3.1.2 adds support for automatic conversion to JSON via Jackson 2.x. There isn’t much that you need to do to make it work, with on caveat.

You need to be using at least Spring 3.1.2 to have Jackson 2.x support. Add the Jackson 2.x dependencies.

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.0.4</version>
        </dependency>

NOTE: If you only include the jackson-core artifact and do not include the jackson-databind artifact, your spring requests will return HTTP 406 errors and there will be no indication of what the real problem is.

What happens if you don’t include jackson-databind? The tag will not instantiate a MappingJackson2JsonView because it has an import for com.fasterxml.jackson.databind.ObjectMapper. There is no message because it just thinks that you are not using that.

Your spring mvc context should already have the .

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc     http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.appriss.jxp"/>
    <mvc:annotation-driven/>

    <!-- Resolves view names for views returned by controllers -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:viewClass="org.springframework.web.servlet.view.JstlView"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp"/>
</beans>

Create a controller method. There are 2 things that must be done. First, specify that the method does produce json as the output. That will map against the “accept-header: application/json”. Then have the method return an object instead of a ModelAndView object. Annotate that object with @ResponseBody.

    /**
     * Returns a json list of first names.
     * @param term the beginning part of the first name
     * @return json string array of first names
     */
    @RequestMapping(value = "/first", produces = "application/json")
    public @ResponseBody List<String> firstNames(@RequestParam String term) {
        return nameDao.getFirstNames(term);
    }

There you have it. The rest is automatic.

July 15th, 2012

Posted In: Java, json, Spring

14 Comments

It has been a while since I wrote a form. I kept posting data even though the Jquery Validation fired and was not valid. I forgot that you have to check for a valid form. I also learned that you can also add a submit handler to the validation call. Here is what the completed validation and ajax call looked like. Notice that in this form, I disable the submit button belonging to the form just before the ajax request is sent.

$(document).ready(function () {
    $("#expungementForm").validate({
        submitHandler: function(form) {
            $.ajax({
                cache: false,
                type: "POST",
                url: form.action,
                data: $(form).serialize(),
                beforeSend: function (jqXHR, settings) {
                    $('input[type="submit"]', form).attr('disabled', true);
                },
                success: function (data) {
                    $('#expungeResult').html(data)
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    $('#expungeResult').html(textStatus).append("...").append(errorThrown).css('color', 'red')
                }});
            return false;
        }
    });
});

June 13th, 2012

Posted In: HTML, javascript, JQuery, json

Tags: , , , , ,

Leave a Comment

LinkedIn Auto Publish Powered By : XYZScripts.com