Jersey/JAXB 讨厌矩形

Jersey/JAXB hates Rectangle

我有一个 Java 应用程序,它使用 Jersey 来提供 REST 服务。我有几个 REST 端点,所有这些端点 return 有效 JSON (所需格式)。我们有一个新的端点,一个 GET,return 有效 JSON,除了一个元素,一个 Java 矩形。这是我们得到的响应:

[
    {
        "customers": {
            "current": 2,
            "max": 16
        },
        "format": "ABCD",
        "dataPoints": 20,
        "window": "java.awt.Rectangle[x=50,y=50,width=400,height=300]"
    }
]

如您所见,矩形无效 JSON。我尝试了几件事,但 none 奏效了。我尝试过的事情包括在 class 上的矩形元素上添加 @XmlRootElement@XmlElement@XmlAttribute。唯一要做的就是将格式错误的 JSON 移动到输出的顶部。

我怀疑它不起作用,因为矩形 class 在其 class 声明中没有 @XmlRootElement,因此 JAXB 无法将其正确转换为 XML(然后进入JSON)。如果是这种情况,我是否需要从 Rectangle 继承只是为了包含该注释? JAXB 开发人员似乎已经考虑了内置类型。我的假设是否正确,或者是否有其他解决方案?

另一种解决方案可能是自己进行 JSON 转换,然后 return JSON 字符串作为响应的实体,如下所示。

@Path("/rectangle")
@Produces(MediaType.APPLICATION_JSON)
@GET
public Response getRect() {

    Rectangle r = new Rectangle();
    Gson gson = new Gson();
    String jsonRect = gson.toJson(r);
    return Response.status(Status.OK).entity(jsonRect).build();
}

因此根本不使用 JAXB。

按照this article你可以这样解决问题

JAXB 开箱即用,无法 marshall/unmarshall java.awt.Rectangle

因为我们无法更改 Rectangle class,我们将编写新的 class、MyRectangle,JAXB 知道如何 marshall/unmarshall。

public class MyRectangle {

    private int x;
    private int y;
    private int width;
    private int height;

    public MyRectangle() {
    }

    public MyRectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}

然后我们需要 XmlAdapterRectangleMyRectangle 之间转换:

public class RectangleXmlAdapter extends XmlAdapter<MyRectangle, Rectangle> {

    @Override
    public Rectangle unmarshal(MyRectangle v) throws Exception {
        if (v == null)
            return null;
        return new Rectangle(v.getX(), v.getY(), v.getWidth(), v.getHeight());
    }

    @Override
    public MyRectangle marshal(Rectangle v) throws Exception {
        if (v == null)
            return null;
        return new MyRectangle(v.x, v.y, v.width, v.height);
    }
}

最后,你使用 @XmlJavaTypeAdapter 注释告诉 JAXB 在 marshalling/unmarshalling 时使用我们的 RectangleXmlAdapter Rectangle 属性。例如:

@XmlJavaTypeAdapter(RectangleXmlAdapter.class)
private Rectangle window;

那么这个 window 属性 会有这样的 XML 表示:

<window>
    <x>50</x>
    <y>50</y>
    <width>400</width>
    <height>300</height>
</window>

然后(通过一些 Jersey-magic)这样的 JSON 表示:

"window": {
    "x": 50,
    "y": 50,
    "width": 400,
    "height": 300
}