Jackson MixIn will replace the generic JAXBElement <T> with its own T for getValue ()

I am trying to bind XML and JSON using the same JAXB annotations (using JaxbAnnotationModule ).

XML <--> JAXB <--> Jackson <--> JSON

      

I have to use JAXB annotation and cannot change them. My problem is that some XML files are directly converted to a generic class JAXBElement<T>

instead of a class T

. This results in JSON output:

{  
   "JAXBElement":{  
      "name":"{http://www.opengis.net/wps/1.0.0}Capabilities",
      "declaredType":"net.opengis.wps.v_1_0_0.WPSCapabilitiesType",
      "scope":"javax.xml.bind.JAXBElement$GlobalScope",
      "value":{  
         "ProcessOfferings":{  },
         "Languages":{  },
         "ServiceIdentification":{  },
         "ServiceProvider":{  },
         "OperationsMetadata":{  },
         "version":"1.0.0",
         "updateSequence":"1",
         "service":"WPS",
         "lang":"en-US"
      },
      "nil":false,
      "globalScope":true,
      "typeSubstituted":false
   }
}

      

As long as I want:

{  
   "Capabilities":{  
     "ProcessOfferings":{  },
     "Languages":{  },
     "ServiceIdentification":{  },
     "ServiceProvider":{  },
     "OperationsMetadata":{  },
     "version":"1.0.0",
     "updateSequence":"1",
     "service":"WPS",
     "lang":"en-US"
   }
}

      

The real object of the type is T

wrapped in JAXBElement. This can happen for some root elements, as well as objects nested in the tree. If I call getValue()

, I get a real object. But I cannot do this when JAXBElement<T>

not the root element, since Jackson is the only interpreter between JAXB and JSON, and I can neither modify the JAXB-Binding nor the created objects (some other parts of the code use them, too).

So what I found that can solve the problem is MixIns :

// a mixin annotation that overrides the handling for the JAXBElement
public static interface JAXBElementMixin<T> {
    @JsonValue
    Object getValue();
}

ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
mapper.addMixInAnnotations(JAXBElement.class, JAXBElementMixin.class);

      

This solves the extra items problem, but results in the object name JAXBElement

instead of T

(in my case Capabilities

):

{  
  "JAXBElement":{  // <------ Should be 'Capabilities' because of type JAXBElement<Capabilities>
    "ProcessOfferings":{  },
    "Languages":{  },
    "ServiceIdentification":{  },
    "ServiceProvider":{  },
    "OperationsMetadata":{  },
    "version":"1.0.0",
    "updateSequence":"1",
    "service":"WPS",
    "lang":"en-US"
  }
}

      

Questions:

Any idea what I can do (possibly annotate JAXBElementMixin<T>

) to get the correct type Capabilities

as the object name (there are other classes instead of Capabilities

which could also be put like T

)?

Any other idea how to skip serializing any anywhere JAXBElement<T>

in the object tree and continue serializing the object by its method getValue()

?

+3


source to share


2 answers


This is not a direct answer to your question, but perhaps a recipe for achieving your goal.

If you just want to get rid of the topmost one JAXBElement

, why not just tweak XJC to create an additional class for your element Capabilities

?

Something like:



<jaxb:bindings node="xs:element[@name='Capabilities']">
   <jaxb:class name="Capabilities"/>
</jaxb:bindings>

      

This should generate a class Capabilities

annotated with "@XmlRootElement". This way you get rid of JAXBElement

.

0


source


Jackson does not support JAXBElement

it as it is very XML specific and difficult to work with other formats: Jackson's JAXB support focuses on using information from annotations to make things work, but the goal should not be a complete JAXB implementation.



Thus, it is best to do what @lexicore suggests and try to avoid using JAXBElement

.

0


source







All Articles