使用 Decorator 进行 JBoss RESTeasy JAX-RS JAXB 模式验证
我正在尝试验证在 JBoss AS 7 内运行的应用程序中通过我的(合同优先)REST 接口传入的所有传入 XML 文件。我已经编写了一个用于漂亮打印的 @Decorator (如 JBoss RESTeasy 文档中的示例)并且类似的,用于为解组器打开 XML 模式验证。不幸的是,解组器的装饰器从未被调用。
这是 Pretty Decorator 的代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Marshaller;
import org.jboss.resteasy.annotations.Decorator;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Decorator(processor = PrettyProcessor.class, target = Marshaller.class)
public @interface Pretty {}
和实现:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
@DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> {
private static final Logger LOGGER = Logger.getLogger(PrettyProcessor.class);
@Override
public Marshaller decorate(Marshaller target, Pretty annotation, Class type, Annotation[] annotations, MediaType mediaType) {
LOGGER.debug("Pretty.");
try {
target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
} catch (PropertyException e) {
}
return target;
}
}
现在是 Validate 的注释(不起作用):
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Unmarshaller;
import org.jboss.resteasy.annotations.Decorator;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Decorator(processor = ValidateProcessor.class, target = Unmarshaller.class)
public @interface Validate {}
实现:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import javax.xml.XMLConstants;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
import org.xml.sax.SAXException;
@DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class ValidateProcessor implements DecoratorProcessor<Unmarshaller, Validate> {
private static final Logger LOGGER = Logger.getLogger(ValidateProcessor.class);
@Override
public Unmarshaller decorate(Unmarshaller target, Validate annotation, Class type, Annotation[] annotations, MediaType mediaType) {
target.setSchema(getSchema());
LOGGER.debug("Set validation schema.");
System.out.println("Set validation schema.");
return target;
}
}
和 REST 接口的代码:
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.xml.ws.WebServiceException;
@Path("/{mdvt}/{ouid}/order")
public interface OrderResource {
@RolesAllowed({ "mpa" })
@POST
@Path("/update")
@Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@Produces(MediaType.APPLICATION_XML)
@Pretty
public Response update(@Context SecurityContext sec,
@PathParam("ouid") String ouID,
@PathParam("mdvt") long masterDataVersionTag,
@Validate UpdateOrdersRequest uor) throws WebServiceException;
}
在同一个 REST 方法上,(更新) @Pretty Decorator被调用,而 @Validate 则不会。我在这里做错了什么?
我发现了一个旧错误 Decorator for Jaxb unmarshaller does not work 已关闭。
那里的评论说一切正常,上面的代码几乎与那里的代码完全相同,包括解决方案。然而,Unmarshaller 没有任何作用。
I am trying to validate all incoming XML files that come over my (contract first) REST interface in an application running inside JBoss AS 7. I have written a @Decorator for Pretty-Printing (as by the example in the JBoss RESTeasy documentation) and an analogous one for switching on XML schema validation for the unmarshaller. Unfortunately, the decorator for the unmarshaller is never called.
Here is the code for the Pretty Decorator:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Marshaller;
import org.jboss.resteasy.annotations.Decorator;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Decorator(processor = PrettyProcessor.class, target = Marshaller.class)
public @interface Pretty {}
And the implementation:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
@DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class PrettyProcessor implements DecoratorProcessor<Marshaller, Pretty> {
private static final Logger LOGGER = Logger.getLogger(PrettyProcessor.class);
@Override
public Marshaller decorate(Marshaller target, Pretty annotation, Class type, Annotation[] annotations, MediaType mediaType) {
LOGGER.debug("Pretty.");
try {
target.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
} catch (PropertyException e) {
}
return target;
}
}
Now the annotation for the Validate (that does not work):
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.bind.Unmarshaller;
import org.jboss.resteasy.annotations.Decorator;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Decorator(processor = ValidateProcessor.class, target = Unmarshaller.class)
public @interface Validate {}
The implementation:
import java.lang.annotation.Annotation;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import javax.xml.XMLConstants;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.log4j.Logger;
import org.jboss.resteasy.annotations.DecorateTypes;
import org.jboss.resteasy.spi.interception.DecoratorProcessor;
import org.xml.sax.SAXException;
@DecorateTypes({ "text/*+xml", "application/*+xml", MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class ValidateProcessor implements DecoratorProcessor<Unmarshaller, Validate> {
private static final Logger LOGGER = Logger.getLogger(ValidateProcessor.class);
@Override
public Unmarshaller decorate(Unmarshaller target, Validate annotation, Class type, Annotation[] annotations, MediaType mediaType) {
target.setSchema(getSchema());
LOGGER.debug("Set validation schema.");
System.out.println("Set validation schema.");
return target;
}
}
And the code of the REST interface:
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.xml.ws.WebServiceException;
@Path("/{mdvt}/{ouid}/order")
public interface OrderResource {
@RolesAllowed({ "mpa" })
@POST
@Path("/update")
@Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@Produces(MediaType.APPLICATION_XML)
@Pretty
public Response update(@Context SecurityContext sec,
@PathParam("ouid") String ouID,
@PathParam("mdvt") long masterDataVersionTag,
@Validate UpdateOrdersRequest uor) throws WebServiceException;
}
On the same REST method, (update) the @Pretty Decorator gets called while the @Validate does not. What am I doing wrong here?
I have found an old bug Decorator for Jaxb unmarshaller doesn't work which is closed.
The comments there say that everything works, and the code above is almost exactly the one from there, including the solution. Nevertheless, nothing works for the Unmarshaller.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
最后,这个问题在 JBoss AS 7 中得到了解决。
问题出在 Resteasy 实现上,直到版本 2.3.5.Final 为止,该实现都存在错误。
请参阅 https://issues.jboss.org/browse/RESTEASY-711 但忽略提到的解决方法,直到版本 2.3.5 才起作用。
可行的解决方案是下载 Restwasy 发行版 2.3.5.Final 或更高版本,解压并查找resteasy-jboss-modules-2.3.5.Final.zip
将此文件解压到 JBoss AS 7.1.1 和 Resteasy 的根目录中将更新至新版本。完成这一步后,以上所有代码就可以正常工作了。
感谢比尔·伯克(Bill Burke)为我指出了解决方案,
Finally this problem was resolved for JBoss AS 7.
The problem lies in the Resteasy implementation which is buggy until version 2.3.5.Final.
See https://issues.jboss.org/browse/RESTEASY-711 but ignore the mentioned workaround, it does not work until version 2.3.5.
The working solution is to download the Restwasy distribution version 2.3.5.Final or above, extract it and look for resteasy-jboss-modules-2.3.5.Final.zip
Extract this file in the root of JBoss AS 7.1.1 and resteasy will be updated to the new version. After this step, all of the above code just works.
Thanks to Bill Burke to point me to the solution,
您可以实现一个
MessageBodyReader
,它在 JAXBUnmarshaller
上设置Schema
来执行验证。有关示例代码,请查看我对类似问题的回答:You could implement a
MessageBodyReader
that sets anSchema
on the JAXBUnmarshaller
to perform validation. For sample code check out my answer to a similar question: