Search code examples
javaxmlinheritancereflectionxml-binding

Is it justified to use Reflection in this use case to workaround design issue that i am not allowed to fix?


Would the following use case be considered as justified for Reflection?

There are bunch of classes generated from XSDs (hundreds currently on project) which represent various Responses.

All of these Responses include common response data structure, rather then extending it.

When event such as timeout happens, i only need to set single String to specific value.

If these classes were extending common response structure i could always set this response code without reflection, but this is not the case.

Therefore i wrote simple utility for my services which uses reflection to get setter method for the String field and invoke it with predefined value. Only known alternative to me would be to have class specific methods which would duplicate code to handle timeout, with the only difference of returned Response class.

protected T handleTimeout(Class<T> timeoutClass) {
    try {
        T timeout = timeoutClass.newInstance();
        Method setCode = timeoutClass.getDeclaredMethod(SET_RESPONSE_CODE, String.class);
        setCode.invoke(timeout, Response.TIMEOUT.getCode());
        return timeout;
    } catch (InstantiationException | IllegalAccessException  | SecurityException | NoSuchMethodException | IllegalArgumentException | InvocationTargetException e) {
        e.printStackTrace();
        throw new RuntimeException("Response classes must have field: \"code\" !");
    }

}

Relevant fact:

  • this setter method should never change as it would require rework of hundreds of interfaces

Could somebody point out if there are some pitfalls i have missed or if there is alternate solution for reflection which would achieve the same result ?

Edit: I simply have no authority to get any changes done on XSDs, so any solution would have to be done locally. There should be no problems with serializing such objects, as they are shared between components.


Solution

  • I'd try an alternate solution for generating your classes from the xml schema, in preference over reflection.

    You can supply xjc with a custom binding like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <bindings xmlns="http://java.sun.com/xml/ns/jaxb"
          xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
          xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd" version="2.1">
        <globalBindings>
            <xjc:superClass name="XmlSuperClass" />
        </globalBindings>
    </bindings>
    

    and implement you XmlSuperClass like this:

    @XmlTransient                     // to prevent that the shadowed responseCode be marshalled
    public class XmlSuperClass {
        private String responseCode;         // this will be shadowed
        public String getResponseCode() {    // this will be overridden
            return responseCode;
        }
        public void setResponseCode(String value) { //overridden too
            this.responseCode = value;
        }
    }
    

    Invoking xjc like this:

    xjc -extension -b <yourbinding.xjb> -cp <XmlSuperClass> <xmlschemas.xsd...>
    

    will generate bound classes like:

    @XmlRootElement(name = "whatever")
    public class Whatever extends XmlSuperClass {
        @XmlElement(required = true)
        protected String responseCode;    // shadowing
        public void setResponseCode(String...) //overriding
    }