json - 在 Jersey 2.2 JAX-RS 下使用 JAXB 和 JSON 的命名空间

标签 json namespaces jaxb jersey jax-rs

我正在使用 xjc 编译带有命名空间和任何元素的 XML 模式。我将根据需要包含来自外部命名空间的元素,并需要处理包含元素定义的新版本的情况,或者可能包含来自具有相同名称的另一个命名空间的元素。显然,此 XML 版本运行良好,我为客户端的所有元素获得了正确的 QNAME,但是,对于 JSON,我获得了一个仅包含元素名称的非限定 QNAME。这意味着我无法区分来自一个命名空间的名为“bob”的元素与来自第二个命名空间的名为“bob”的不同元素。

我已经阅读了我能找到的所有 Material ,并相信这是我在服务器端需要做的事情,但是,我不知道我在客户端需要什么:

@Provider
final static class JsonMoxyConfigurationContextResolver implements ContextResolver<MoxyJsonConfig> {

    @Override
    public MoxyJsonConfig getContext(Class<?> objectType) {
        final MoxyJsonConfig configuration = new MoxyJsonConfig();

        Map<String, String> namespacePrefixMapper = new HashMap<String, String>(2);
        namespacePrefixMapper.put("http://schema.jaxbmoxy.examples.jersey.glassfish.org/2013/08/customer", "c");
        namespacePrefixMapper.put("http://schema.jaxbmoxy.examples.jersey.glassfish.org/2013/08/other", "o");

        configuration.setNamespacePrefixMapper(namespacePrefixMapper);
        configuration.setNamespaceSeparator('.');

        return configuration;
    }
}

“c”模式是我定义的基本模式,“o”模式包含我将通过 ANY 合并的元素定义。对于下面的示例,我从外部命名空间导入 o.stats 和 o.email。下面是服务器端生成的 JSON:
{"c.customer": [
    {
        "id": "3",
        "personal-info": {
            "name": "Bobby Boogie",
            "o.stats": [{
                "age": "45",
                "height": "160 cm",
                "weight": "70 kg"
            }]
        },
        "contact-info": {
            "address": {
                "city": "My Town",
                "street": "123 Any Street",
                "country": "CA"
            },
            "phone-number": [
                {
                    "type": "work",
                    "value": "613-555-1111"
                },
                {
                    "type": "cell",
                    "value": "613-555-2222"
                }
            ]
        }
    },
    {
        "id": "2",
        "personal-info": {
            "name": "Fred Finkleman",
            "o.stats": [{
                "age": "55",
                "height": "182 cm",
                "weight": "86 kg"
            }]
        },
        "contact-info": {
            "address": {
                "city": "Fredsville",
                "street": "1 Happy Street",
                "country": "US"
            },
            "phone-number": [
                {
                    "type": "work",
                    "value": "613-555-1111"
                },
                {
                    "type": "cell",
                    "value": "613-555-2222"
                }
            ],
            "o.email": ["fred@email.com"]
        }
    },
    {
        "id": "1",
        "personal-info": {
            "name": "Tom Dooley",
            "o.stats": [{
                "age": "45",
                "height": "160 cm",
                "weight": "70 kg"
            }]
        },
        "contact-info": {
            "address": {
                "city": "My Town",
                "street": "123 Any Street",
                "country": "CA"
            },
            "phone-number": [
                {
                    "type": "work",
                    "value": "613-555-1111"
                },
                {
                    "type": "cell",
                    "value": "613-555-2222"
                }
            ]
        }
    }
]}

客户端需要什么配置代码才能使其正常运行?目前我有以下几点:
@Override
protected void configureClient(ClientConfig clientConfig) {
    clientConfig.register(new MoxyXmlFeature());
    new ResourceConfig().property(MarshallerProperties.JSON_NAMESPACE_SEPARATOR, ".");
}

谢谢!

最佳答案

您还需要设置 MarshallerProperties.NAMESPACE_PREFIX_MAPPER属性以匹配您在服务器端设置的属性。

编辑:我觉得上面提供的 Blaise 的答案是正确的,但是,它引入了一个不同的问题,我只能假设它是 Jersey 2.2 下的错误。这是我根据 Blaise 的回答创建的客户端代码段:

@Override
protected void configureClient(ClientConfig clientConfig) {
    Map<String, String> namespacePrefixMapper = new HashMap<String, String>(2);
    namespacePrefixMapper.put("http://schema.jaxbmoxy.examples.jersey.glassfish.org/2013/08/customer", "c");
    namespacePrefixMapper.put("http://schema.jaxbmoxy.examples.jersey.glassfish.org/2013/08/other", "o");

    clientConfig.register(new MoxyXmlFeature());
    clientConfig.register(new MoxyJsonFeature());
    clientConfig.property(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, namespacePrefixMapper);
    clientConfig.property(MarshallerProperties.JSON_NAMESPACE_SEPARATOR, '.');
}

在客户端,我现在在处理传入的 JSON 期间得到一个 NPE:
javax.ws.rs.ProcessingException: Unexpected error during response processing.
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:767)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:90)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:671)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:422)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:667)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:396)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:296)
at org.glassfish.jersey.examples.jaxbmoxy.MoxyAppTest.testJsonCustomer(MoxyAppTest.java:172)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:264)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:443)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:424)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:241)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:443)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:296)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:443)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:424)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:241)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parseRoot(JSONReader.java:174)
at org.eclipse.persistence.internal.oxm.record.json.JSONReader.parse(JSONReader.java:125)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:972)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:425)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:375)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:705)
at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:655)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:301)
at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.readFrom(MOXyJsonProvider.java:580)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:188)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:134)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:988)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:833)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:768)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:96)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:761)
... 41 more

现在一切都没有丢失。我能够通过添加属性前缀处理来解决这个问题。在服务器端,我添加到 JsonMoxyConfigurationContextResolver.getContext():
configuration.setAttributePrefix("@"); 

在客户端,我向 configureClient() 添加了以下内容:
clientConfig.property(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@");

我现在可以正确处理传入的 JSON,并且命名空间已添加到包含的 JAXB 元素的 QNAME。

感谢您的帮助!!

关于json - 在 Jersey 2.2 JAX-RS 下使用 JAXB 和 JSON 的命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18475977/

相关文章:

zend-framework - 如何在 Zend Framework 中使用命名空间?

python - 代码风格 - "flattening"包的命名空间

c# - WPF - namespace 中不存在名称

binding - JAXB 绑定(bind)通用转换器

java - 使用 STAX 解析器将 XML 解码为三个不同对象的列表

java - 如何在 Maven 中表达对 java ee 特性的依赖以过渡到 Java 9?

Java:具有接口(interface)属性的对象的 Jackson 多态 JSON 反序列化?

javascript - 读取api的简单json

javascript - 使用jquery将本地mp3文件发送到api服务器

html - 如何从 iOS 中的文件中解析 JSON?