简体   繁体   中英

override @XmlElement annotation with FIELD accessor type

I have a class with @XmlAccessorType(XmlAccessType.FIELD) annotation, and each private and protected field is annotated with @XmlElement(name='...') .

The challenge: I may want to rename one of the xml element names in a later stage. This leads me to the question. Is there a way to override/redefine these annotations, if I create a sub-class ?

Whilst in java, to my knowledge, overriding an annotation @XmlElement(name='...') to change the name property is not possible; you can create a global variable in your code and either pass it through your classes or your functions following the @XmlElement(name='...') .

In the code below I created a single class but it contains the setter and getter methods required if you want to pass it through to another class

@XMLAccessorType(XMLAccessType.FIELD)
public class YourClass {

    @XmlTransient
    private String string = ""; //This can be replaced with whatever variable you are manipulating
                                //That could be an int or a file or anything really

    @XmlElement(name = "your_name")
    private void doSomething() {
        String temp = getString(); //This variable is normally used to pass between different
                                   //classes but may as well use it if you have one
        //Your code which manipulates the String
        setString(temp); //This variable is normally used to pass between different classes but
                         //may as well use it if you have one
    }


    @XmlElement(name = "your_other_name")
    private void doSomethingElse() {
        String temp = getString();
        //Your code which manipulates the String
        setString(temp);
    }

    public void getString() {
        return string;
    }


    public void setString(String string) {
        this.string = string;
    }

}

I would reccomend looking at the Java Docs for @XmlTransient and these two other relevant SO questions.

How to override JAXB @XMLAccessorType(XMLAccessType.FIELD) specified at a Class level with @XMLElement on a getter method for a property?

Jaxb - Overriding the XMLElement name attribute

I tried first with the @XmlAccessorType(XmlAccessType.FIELD) and to hide with @XmlTransient . This only works, if you mark the field in the superclass and in the child class with @XmlTransient . But I assume, this is not what you want.

As second approach I've tried with more restrictive @XmlAccessorType(XmlAccessType.PROPERTY) in the superclass and @XmlAccessorType(XmlAccessType.NONE) in the child class. See here my example:

package com.so.example;

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

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/myresource")
public class MyResource {

    @GET
    @Path("/car")
    @Produces(MediaType.APPLICATION_XML)
    public Car getCar() {
        Car car = new Car();
        car.setWheels(4);
        return car;
    }

    @GET
    @Path("/suv")
    @Produces(MediaType.APPLICATION_XML)
    public Suv getSuv() {
        Suv suv = new Suv();
        List<String> bigWheels = new ArrayList<>();
        bigWheels.add("left front wheel");
        bigWheels.add("right front wheel");
        bigWheels.add("left rear wheel");
        bigWheels.add("right rear wheel");
        suv.setBigWheels(bigWheels);
        return suv;
    }
}

Class Car:

package com.so.example;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement
public class Car {

    protected Integer wheels;

    public Car() {
    }

    @XmlElement(name = "wheels", nillable = true)
    public Integer getWheels() {
        return wheels;
    }

    public void setWheels(Integer wheels) {
        this.wheels = wheels;
    }
}

Class Suv (Child):

package com.so.example;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Suv extends Car {

    @XmlTransient
    private Integer wheels;

    private List<String> bigWheels;

    public Suv() {
    }

    @Override
    @XmlTransient
    public Integer getWheels() {
        return wheels;
    }

    @Override
    public void setWheels(Integer wheels) {
        this.wheels = wheels;
    }

    @XmlElement
    public List<String> getBigWheels() {
        return bigWheels;
    }

    public void setBigWheels(List<String> bigWheels) {
        this.bigWheels = bigWheels;
    }
}

One way to "hide" the element wheels of the superclass would be to mark it as "nillable=true" and not use primitive types. In this case, the field wheels will be marshalled to <wheels xsi:nil="true"/>

If it's possible for you to not use the parent class for marshalling and you are only using child classes, you could use the approach described here:

http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html

Also you could use moxy and specify a custom binding: http://www.eclipse.org/eclipselink/documentation/2.4/moxy/runtime003.htm

I believe that some implementations of JaxB allow for XML configuration to override the annotations. In this case this may actually be possible. Here is an article from Eclipslink explaining how this can be done http://www.eclipse.org/eclipselink/documentation/2.4/solutions/jpatoxml004.htm

In my opinion you can just build an XML configuration for the JaxB file you want to override.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM