简体   繁体   English

在Jersey 2.2 JAX-RS下将名称空间与JAXB和JSON一起使用

[英]Using namespaces with JAXB and JSON under Jersey 2.2 JAX-RS

I am using xjc to compile an XML schema with namespaces and ANY elements. 我正在使用xjc编译具有名称空间和ANY元素的XML模式。 I will be including elements from external namespaces as needed and need to handle the situation where a new version of an element definition is included, or perhaps a element from another namespace with the same name. 我将根据需要包括来自外部命名空间的元素,并且需要处理其中包含新版本的元素定义,或者可能是来自另一个名称空间的同名元素的情况。 Obviously, the XML version of this is working perfectly and I get the correct QNAME for all elements on the client side, however, for the JSON I get an unqualified QNAME with only the element name present. 显然,它的XML版本运行良好,并且我为客户端的所有元素都获得了正确的QNAME,但是对于JSON,我得到了仅包含元素名称的不合格QNAME。 This means I cannot distinguish between and element called "bob" from one namespace, versus a different element called "bob" from a second namespace. 这意味着我无法区分一个命名空间中的和元素,而第二个命名空间中的和另一个元素“ bob”。

I have read all the material I can find, and believe this is what I need to do on the server side, however, i do not know what I need on the client side: 我已经阅读了所有可以找到的资料,并且相信这是我需要在服务器端执行的操作,但是,我不知道在客户端需要什么:

@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;
    }
}

The "c" schema is the base schema I have defined, and the "o" schema holds the element definitions I will incorporate through the ANY. “ c”模式是我定义的基本模式,“ o”模式保存了将通过ANY合并的元素定义。 For the example below I am importing o.stats and o.email from the external namespace. 对于下面的示例,我将从外部名称空间导入o.stats和o.email。 Below is the JSON being generated on the server side: 以下是在服务器端生成的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"
                }
            ]
        }
    }
]}

What configuration code do I need on the client side so i can get this to function correctly? 我需要在客户端使用什么配置代码,以便我可以使其正常运行? At the moment I have the following: 目前,我有以下内容:

@Override
protected void configureClient(ClientConfig clientConfig) {
    clientConfig.register(new MoxyXmlFeature());
    new ResourceConfig().property(MarshallerProperties.JSON_NAMESPACE_SEPARATOR, ".");
}

Thank you! 谢谢!

You also need to set the MarshallerProperties.NAMESPACE_PREFIX_MAPPER property to match the one you have set on the server side. 您还需要设置MarshallerProperties.NAMESPACE_PREFIX_MAPPER属性,以匹配您在服务器端设置的属性。

Edit: I have a feeling Blaise's answer provided above is correct, however, it introduces a different issue that I can only assume is a bug under Jersey 2.2. 编辑:我觉得上面提供的Blaise答案是正确的,但是,它引入了另一个问题,我只能认为是Jersey 2.2下的错误。 Here is the client code segment I created based on Blaise's answer: 这是我根据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, '.');
}

On the client side I am now getting a NPE during processing of the incoming JSON: 在客户端,我现在在处理传入的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

Now all is not lost. 现在一切都不会丢失。 I was able to fix the issue by adding attribute prefix processing. 我可以通过添加属性前缀处理来解决此问题。 On the server side I added to JsonMoxyConfigurationContextResolver.getContext() : 在服务器端,我添加到JsonMoxyConfigurationContextResolver.getContext()

configuration.setAttributePrefix("@"); 

And on the client side I added the following to configureClient() : 在客户端,我将以下内容添加到configureClient()

clientConfig.property(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, "@");

I am now getting the correct processing of the incoming JSON and the namespace has been added to the QNAME of the included JAXB elements. 现在,我可以正确处理传入的JSON,并将名称空间添加到所包含的JAXB元素的QNAME中。

Thank you for the help!! 感谢您的帮助!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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