本文介绍了JAXB:在解组时拦截?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我有一个使用JAX-RS和JAXB的典型Web服务,在解组时我想知道JAXB显式调用了哪些setter。这有效地让我知道调用者提供的文档中包含哪些元素。 我知道我可以用 XmlAdapter来解决这个问题,但我在很多不同的包中有很多类,我不想为每一个创建适配器。我也不想把钩子放进每一个二传手。如果可能,我想要一个通用的解决方案。请注意,我的所有类都设置为使用getter和setter;他们都没有使用字段作为访问类型。 我的服务使用Jersey 2.4,Spring 3.2和MOXy 2.5.1,所以如果有什么可以从任何地方利用那些,那就更好了。我们最初的想法是,我们可以动态创建一个工厂类(类似于 @XmlType 支持),它将返回一个拦截setter的代理对象。我们认为我们可以使用MOXy中的 MetadataSource 概念来实现这一点,但这似乎不可能。 任何人都有任何想法?解决方案 创建自己的EclipseLink AttributeAccessor MOXy(这是EclipseLink的一个组件)利用一个名为 AttributeAccessor 用字段和属性进行操作。您可以包装此类以捕获所需的所有信息。 import org.eclipse.persistence.exceptions.DescriptorException; import org.eclipse.persistence.mappings.AttributeAccessor; 公共类MyAttributeAccessor扩展AttributeAccessor { private AttributeAccessor attributeAccessor; public MyAttributeAccessor(AttributeAccessor attributeAccessor){ this.attributeAccessor = attributeAccessor; } @Override public Object getAttributeValueFromObject(Object domainObject) throws DescriptorException { return attributeAccessor.getAttributeValueFromObject(domainObject); } @Override public void setAttributeValueInObject(Object domainObject,Object value) throws DescriptorException { System.out.println(Thread: + Thread.currentThread()。getId()+ - 设置值:+ value +on property:+ attributeAccessor.getAttributeName()+for object:+ domainObject); attributeAccessor.setAttributeValueInObject(domainObject,value); } } 告诉MOXy使用你的 AttributeAccessor 我们可以利用 SessionEventListener 来访问底层元数据指定 AttributeAccessor 的实现。这在创建 JAXBContext 时作为属性传入。 Map< ; String,Object> properties = new HashMap< String,Object>(1); properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER,new SessionEventAdapter(){ @Override public void postLogin(SessionEvent event){ Project project = event.getSession( ).getProject(); for(ClassDescriptor descriptor:project.getOrderedDescriptors()){ for(DatabaseMapping mapping:descriptor.getMappings()){ mapping.setAttributeAccessor(new MyAttributeAccessor(mapping) .getAttributeAccessor())); } } super.preLogin(event); } }); JAXBContext jc = JAXBContext.newInstance(new Class [] {Foo.class},properties); 创建时利用JAX-RS ContextResolver JAXBContext 由于您处于JAX-RS环境中,因此您可以利用 ContextResolver 控制如何创建 JAXBContext 。 http://blog.bdoughan.com /2011/04/moxys-xml-metadata-in-jax-rs-service.html 独立示例 Java模型(Foo) 下面是一个示例类,我们将使用字段访问(无设置器)。 import javax.xml.bind.annotation 。*; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Foo { private String bar; private String baz; } 演示 import java.io.StringReader; import java.util。*; import javax.xml.bind。*; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.jaxb.JAXBContextProperties; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.sessions。*; 公共类演示{ public static void main(String [] args)抛出异常{ Map< String,Object> properties = new HashMap< String,Object>(1); properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER,new SessionEventAdapter(){ @Override public void postLogin(SessionEvent event){ Project project = event.getSession( ).getProject(); for(ClassDescriptor descriptor:project.getOrderedDescriptors()){ for(DatabaseMapping mapping:descriptor.getMappings()){ mapping.setAttributeAccessor(new MyAttributeAccessor(mapping) .getAttributeAccessor())); } } super.preLogin(event); } }); JAXBContext jc = JAXBContext.newInstance(new Class [] {Foo.class},properties); Unmarshaller unmarshaller = jc.createUnmarshaller(); StringReader xml = new StringReader(< foo>< bar> Hello World< / bar>< / foo>); Foo foo =(Foo)unmarshaller.unmarshal(xml); } } 输出 线程:1 - 设置值:物业上的Hello World:对象栏:forum21044956.Foo@37e47e38 UPDATE 所以这有效,但我有一些问题。首先,domainObject是,总是在我的系统中记录为0。不确定为什么会这样。 我不知道为什么会发生这种情况,可能需要检查 toString ()表示您正在记录的对象。你需要在这里加强逻辑。基于所设置的对象,你应该能够做你想做的事。你可以缓存创建的 JAXBContext 以防止重建它。 I've got a typical web service using JAX-RS and JAXB, and upon unmarshalling I would like to know which setters were explicitly called by JAXB. This effectively lets me know which elements were included in the document provided by the caller.I know I can probably solve this with an XmlAdapter, but I have a lot of classes in a number of different packages, and I don't want to create adapters for each and every one of them. Nor do I want to put hooks into each and every setter. I would like a general solution if possible. Note that all of my classes are setup to use getters and setters; none of them use fields for the access type.My service uses Jersey 2.4, Spring 3.2, and MOXy 2.5.1, so if there's anything that can be leveraged from any of those, that's all the better. Our original thought was we could dynamically create a factory class (akin to what @XmlType supports) that would return a proxy object that would intercept the setters. We thought we could make this happen using the MetadataSource concept in MOXy, but that does not seem to be possible.Anyone have any ideas? 解决方案Create your own EclipseLink AttributeAccessorMOXy (which is a component of EclipseLink) leverages a class called AttributeAccessor to do operations with fields and properties. You could wrap this class to capture all the information that you need.import org.eclipse.persistence.exceptions.DescriptorException;import org.eclipse.persistence.mappings.AttributeAccessor;public class MyAttributeAccessor extends AttributeAccessor { private AttributeAccessor attributeAccessor; public MyAttributeAccessor(AttributeAccessor attributeAccessor) { this.attributeAccessor = attributeAccessor; } @Override public Object getAttributeValueFromObject(Object domainObject) throws DescriptorException { return attributeAccessor.getAttributeValueFromObject(domainObject); } @Override public void setAttributeValueInObject(Object domainObject, Object value) throws DescriptorException { System.out.println("Thread: " + Thread.currentThread().getId() + " - Set value: " + value + " on property: " + attributeAccessor.getAttributeName() + " for object: " + domainObject); attributeAccessor.setAttributeValueInObject(domainObject, value); }}Tell MOXy to use your AttributeAccessorWe can leverage a SessionEventListener to access the underlying metadata to specify your implementation of AttributeAccessor. This is passed in as a property when creating the JAXBContext. Map<String, Object> properties = new HashMap<String, Object>(1); properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER, new SessionEventAdapter() { @Override public void postLogin(SessionEvent event) { Project project = event.getSession().getProject(); for(ClassDescriptor descriptor : project.getOrderedDescriptors()) { for(DatabaseMapping mapping : descriptor.getMappings()) { mapping.setAttributeAccessor(new MyAttributeAccessor(mapping.getAttributeAccessor())); } } super.preLogin(event); } }); JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties);Leverage a JAX-RS ContextResolver when Creating the JAXBContextSince you are in a JAX-RS environment you can leverage a ContextResolver to control how the JAXBContext is created.http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.htmlStandalone ExampleJava Model (Foo)Below is a sample class where we will use field access (no setters).import javax.xml.bind.annotation.*;@XmlRootElement@XmlAccessorType(XmlAccessType.FIELD)public class Foo { private String bar; private String baz;}Demo import java.io.StringReader;import java.util.*;import javax.xml.bind.*;import org.eclipse.persistence.descriptors.ClassDescriptor;import org.eclipse.persistence.jaxb.JAXBContextProperties;import org.eclipse.persistence.mappings.DatabaseMapping;import org.eclipse.persistence.sessions.*;public class Demo { public static void main(String[] args) throws Exception { Map<String, Object> properties = new HashMap<String, Object>(1); properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER, new SessionEventAdapter() { @Override public void postLogin(SessionEvent event) { Project project = event.getSession().getProject(); for(ClassDescriptor descriptor : project.getOrderedDescriptors()) { for(DatabaseMapping mapping : descriptor.getMappings()) { mapping.setAttributeAccessor(new MyAttributeAccessor(mapping.getAttributeAccessor())); } } super.preLogin(event); } }); JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties); Unmarshaller unmarshaller = jc.createUnmarshaller(); StringReader xml = new StringReader("<foo><bar>Hello World</bar></foo>"); Foo foo = (Foo) unmarshaller.unmarshal(xml); }}OutputThread: 1 - Set value: Hello World on property: bar for object: forum21044956.Foo@37e47e38UPDATEI have not idea why that is occuring, may need to check the toString() for the object you are logging.You will need to beef up the logic here. Based on the objects being set you should be able to do what you want.You can cache the created JAXBContext to prevent rebuilding it. 这篇关于JAXB:在解组时拦截?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-07 16:53