如何控制 JAX-WS 中的 JAXBContext?

发布于 2024-12-03 02:02:21 字数 794 浏览 1 评论 0原文

我需要为每个客户部署相同的 Web 服务。此 @javax.jws.WebService 使用 Object 作为方法参数和返回类型(导致 wsdl 中的 ) 。 Web 服务的每个实例都与客户的 jar 一起部署在类路径上。该 jar 具有已知的结构,并包含客户端希望通过我的服务处理的 JAXB 注释的类。

问题是,当客户将其类的实例作为方法参数传递时,服务器端 JAXB 上下文将其解组到一些奇怪的 xerces dom 节点中,因为(据我所知)在部署期间只有 @WebMethod@WebService 注释被扫描,正如已经说过的,它们都只处理 Object

简而言之,我需要在 WEB-INF/lib/customer_classes_14586.jar 处提示 JAXB,这意味着在 JAX-WS 部署期间对 JAXBContext 创建进行一些控制。

有可能吗?

特定于服务器的解决方案很好(带有 Metro ws 堆栈的 glassfish 3.1)

更新

我错过了一件可能很重要的事情:我在运行时通过 Web 管理控制台将这些 Web 服务部署为 OSGI 捆绑包。当我按下部署按钮时,新的 jar 会以编程方式从客户库、Web 服务类、wsdl 和清单中构建。因此,如果有帮助的话,我可以干预构建过程并在此时提供提示信息。

I need to deploy the same web service for each customer. This @javax.jws.WebService uses Object as method arguments and return types (resulting in <xs:anyType/> in wsdl). Each instance of web service is deployed along with customer's jar on the classpath. This jar has known structure and contains JAXB-annotated classes which client wants to handle via my service.

The problem is that when customer passes an instance of his class as method agrument, server-side JAXB context unmarshals it into some strange xerces dom node because (as I understand it) during the deployment time only @WebMethod and @WebService annotations were scanned which, as was already said, are all dealing with Object only.

Simply speaking, I need to hint JAXB at WEB-INF/lib/customer_classes_14586.jar which means taking some control over JAXBContext creation during JAX-WS deployment.

Is it possible at all?

Server-specific solutions are fine (glassfish 3.1 with metro ws stack)

UPDATE

I've missed one thing that might be important: I deploy these web services as OSGI bundles at runtime via web admin console. When I press deploy button new jar is programmatically built up from customer library, webservice class, wsdl and manifests. So I could interfere in build process and provide hinting information at this point of time if this helps.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

死开点丶别碍眼 2024-12-10 02:02:21

第一个选项是 @UsesJAXBContext 注释。更多信息请参见:在 SLSB 和 JAX 中指定 JAXB 包 - WS

我还没有测试它,因为当我发现这个注释时,我已经转向其他解决方案,这可能对其他人有帮助。

关键是使用 @WebServiceProvider 而不是 @WebService,有点低级但简单:

@WebServiceProvider(
  wsdlLocation = "WEB-INF/wsdl/injector.wsdl"
)
@ServiceMode(value = Service.Mode.PAYLOAD)
public class InjectorService implements Provider<Source> {
  private Unmarshaller unmarshaller;

  @Override
  public Source invoke(Source request) {
    try {
      DOMResult requestDom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(request, requestDom);
      Node requestNode = requestDom.getNode();
      // Get the operation name node.
      Node operationNode = requestNode.getFirstChild();
      // Get the parameter node.
      Node parameterNode = operationNode.getFirstChild();
      // Unmarshal
      JAXBElement<Object> element = unmarshaller.unmarshal(parameterNode, Object.class);
      Object unmarshalled = element.getValue();          

      //  Handling customer object and response ......
    } catch (Exception e) {
      throw new RuntimeException("Endpoint error", e);
    }
  }

  protected Class[] getCustomerClasses() {
    // return customer classes somehow
  }

  @PostConstruct
  public void init() throws Exception {
    JAXBContext jbc = JAXBContext.newInstance(getCustomerClasses());
    unmarshaller = jbc.createUnmarshaller();
  }
}

就是这样。客户类可以从类路径、捆绑上下文等获取。

First option is @UsesJAXBContext annotation. More info here: Specify JAXB Packages in SLSB and JAX-WS

I haven't tested it cause when I found this annotation I've been already halfway towards other solution which might be helpful for others.

The key is using @WebServiceProvider instead of @WebService, a bit low-level but simple:

@WebServiceProvider(
  wsdlLocation = "WEB-INF/wsdl/injector.wsdl"
)
@ServiceMode(value = Service.Mode.PAYLOAD)
public class InjectorService implements Provider<Source> {
  private Unmarshaller unmarshaller;

  @Override
  public Source invoke(Source request) {
    try {
      DOMResult requestDom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(request, requestDom);
      Node requestNode = requestDom.getNode();
      // Get the operation name node.
      Node operationNode = requestNode.getFirstChild();
      // Get the parameter node.
      Node parameterNode = operationNode.getFirstChild();
      // Unmarshal
      JAXBElement<Object> element = unmarshaller.unmarshal(parameterNode, Object.class);
      Object unmarshalled = element.getValue();          

      //  Handling customer object and response ......
    } catch (Exception e) {
      throw new RuntimeException("Endpoint error", e);
    }
  }

  protected Class[] getCustomerClasses() {
    // return customer classes somehow
  }

  @PostConstruct
  public void init() throws Exception {
    JAXBContext jbc = JAXBContext.newInstance(getCustomerClasses());
    unmarshaller = jbc.createUnmarshaller();
  }
}

That's it. Customer classes can be obtained from classpath, bundle context or whatever.

墨小沫ゞ 2024-12-10 02:02:21

据我所知,除了您按照 JAX-WS 或 JAXB 已有的方式(您正在寻找的方式)之外,没有任何“声明性”方式来暗示另一种解组方式。顺便说一句,“奇怪的”Xerces 节点实际上是预期的,因为 xsd:any/anyType 和 Object 在您的场景中齐头并进。

我的建议是使用一个相对简单且可移植的解决方案:在通用 Web 方法中构建您自己的薄“绑定”层。它对入站所做的全部工作就是根据其他 JAXB 绑定将 XML 节点解组到 Java 类。然后,它必须从 WS 堆栈解组的 DOM 元素的 QName 中查找 Java 包名称(对于您的 JAXBContext)。查找可以使用属性文件、反射或特定于您的部署的任何其他机制。对于出站(返回),您可以应用反向逻辑来编组响应。这种方法实际上很常见,特别是当其他类型的不受支持的 XML 绑定技术通过标准 WS 堆栈“隧道传输”时。

From what I know, there is no "declarative" way of hinting an alternative way to unmarshall, on top of the one you already have in place as per JAX-WS, or JAXB - what you're looking for. By the way, the "strange" Xerces node is actually expected, since xsd:any/anyType and Object go hand in hand in your scenario.

My suggestion is to use a relatively simple and portable solution: build your own thin "binding" layer inside your generic web method. All it does for the inbound, is to do the unmarshalling of the XML node to the Java class as per your other JAXB bindings. It must then lookup a Java package name (for your JAXBContext) from the QName of the DOM Element unmarshalled by your WS stack. The lookup can use properties file, reflection or any other mechanism specific to your deployment. For the outbound (return) you then apply a reverse logic to marshall the response. This approach is actually quite common, particularly when other type of unsupported-XML bindings technologies are "tunnelled" through a standard WS stack.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文