本文介绍了通过JAXB将链接插入RESTEasy XML结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我想通过 RESTeasy / JAXB 将链接插入XML。我尝试使用文档代码,但是没有用,所以我只是编写了文档中给出的例子:它仍然不起作用,我不明白为什么。I want to insert links into XML via RESTeasy / JAXB. I tried to use the documentation for my code, but that did not work, so I just coded the given examples in the documentation: it still does not work and I have no idea why.要在我的JBoss RESTEasy API中实现HATEOAS原则,我必须在我的JAXB XML结果中插入链接,以便客户端可以浏览API。To implement the HATEOAS principles into my JBoss RESTEasy API I have to insert links into my JAXB XML results, so clients can navigate through the API.我现在正试图了解如何做到这一点,但我不确定文档充满了错误,或者我无法理解这些示例和解释:I am now trying to understand how to do that, but I am not sure if the documentation is full of errors or I am just not able to understand the examples and explanations:根据我的理解,你必须使用 @AddLinks 来声明结果应该插入链接。然后我必须用 @LinkResource 再次再次(!?)和有时指定哪个类 URI构建过程应该来自(例如 @LinkResource(value = car.class))。然后我必须在实体类中添加一个 RESTServiceDiscovery ,用 @XmlElementRef 注释它......但在示例中声明(!?)后, RESTServiceDiscovery 根本没有被使用。As I understand it you have to use @AddLinks to declare that a result should have links inserted. Then I have to do that redundantly again (!?) with @LinkResource and "sometimes" specify which class the URI building process should come from (e.g. @LinkResource(value = car.class)). Then I have to add a RESTServiceDiscovery into the entity class, annotate it with @XmlElementRef... but in the examples RESTServiceDiscovery gets not used at all after declaring (!?).我真的很困惑如何使用这一切,但当然我自己尝试了很多代码,以使其工作。 以下代码就像文档一样示例:I am really confused how to use all that, but of course I tried a lot of code myself, to get it to work.The following code is just like the docu example: BookController.javaimport java.util.ArrayList;import java.util.Collection;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.PathParam;import javax.ws.rs.Produces;import org.jboss.resteasy.links.AddLinks;import org.jboss.resteasy.links.LinkResource;import com.gasx.extsys.datamodel.vo.kplan.Book;@Path("/")@Consumes({ "application/xml", "application/json" })@Produces({ "application/xml", "application/json" })public class BookController { @AddLinks @LinkResource(value = Book.class) @GET @Path("books") public Collection<Book> getBooks() { ArrayList<Book> res = new ArrayList<Book>(); res.add(new Book("Robert", "WhySOIsGreat")); res.add(new Book("Robert", "JavaUltimateGuide")); res.add(new Book("Not Robert", "ThisIsSparta!")); return res; }; @AddLinks @LinkResource @GET @Path("book/{id}") public Book getBook(@PathParam("id") String id) { return new Book("Robert", "WhyIloveJAVA"); };} Book.java :import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlElementRef;import javax.xml.bind.annotation.XmlID;import javax.xml.bind.annotation.XmlRootElement;import org.jboss.resteasy.links.RESTServiceDiscovery;@XmlRootElement@XmlAccessorType(XmlAccessType.NONE)public class Book { @XmlAttribute private String author = "startAuthor"; @XmlID @XmlAttribute private String title = "startTitle"; @XmlElementRef private RESTServiceDiscovery rest; public Book() { } public Book(String author, String title) { this.author = author; this.title = title; }}现在拨打 GET 在图书或 book / 1 会抛出此错误:Now calling a GET on books or book/1 throws this error:2014-09-25 11:30:36,188 WARN [http-/0.0.0.0:8080-1] (org.jboss.resteasy.core.SynchronousDispatcher:135) # Failed executing GET /book/1: org.jboss.resteasy.plugins.providers.jaxb.JAXBMarshalException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptionsXmlElementRef points to a non-existent class.我不确定这个 的工作原理,所以我尝试添加使用 Book.java 中的以下代码手动执行URI:I am not sure how this could work, so I tried adding the URI manually with following code in the Book.java:import java.net.URI; public Book(String author, String title) { this.author = author; this.title = title; URI uri = URI.create("books/" + title); rest = new RESTServiceDiscovery(); rest.addLink(uri, "self"); }但这仍然会引发同样的错误。But this still throws the same error.推荐答案我对链接注入不太熟悉,但添加链接的一种简单方法是嵌入 javax.ws.rs.core.Link s 进入JAXB实体类。它内置了一个XmlAdapter, Link.JaxbAdapter 将允许JAXB对 Link 类型进行编组和解组。例如,您有一个 BookStore 类,其中包含 Books 的集合。它还有 Link ,您可以从中控制导航案例。I'm not too familiar with link injection, but one easy way to add links is to embed javax.ws.rs.core.Links into your JAXB entity classes. It comes with a built in XmlAdapter, Link.JaxbAdapter that will allow the Link type to be marshalled and unmarshalled by JAXB. Take for example you have a BookStore class that holds a collection of Books. It will also have Links from which you can control the navigational cases.@XmlRootElement(name = "bookstore")public class BookStore { private List<Link> links; private Collection<Book> books; @XmlElementRef public Collection<Book> getBooks() { return books; } public void setBooks(Collection<Book> books) { this.books = books; } @XmlElement(name = "link") @XmlJavaTypeAdapter(Link.JaxbAdapter.class) public List<Link> getLinks() { return links; } public void setLinks(List<Link> links) { this.links = links; } @XmlTransient public URI getNext() { if (links == null) { return null; } for (Link link : links) { if ("next".equals(link.getRel())) { return link.getUri(); } } return null; } @XmlTransient public URI getPrevious() { if (links == null) { return null; } for (Link link : links) { if ("previous".equals(link.getRel())) { return link.getUri(); } } return null; }} 预订 class只是一个普通的根元素JAXB类The Book class is just a regular root element JAXB class@XmlRootElementpublic class Book { @XmlAttribute private String author; @XmlAttribute private String title; public Book() {} public Book(String title, String author) { this.title = title; this.author = author; }}在 BookResource class,我们基本上可以根据您想要表示的链接所需的逻辑按需添加链接。在下面的示例中,有一个内存数据库(此类仅用作有状态单例类)的书籍,我为其添加了五本书,并增加了ID。当请求进入时,将在返回的 BookStore 中添加一个或两个链接。根据请求的ID,我们将添加下一个和/或之前的链接。链接将具有我们从 rel c $ c> BookStore class。In the BookResource class, we can basically add links on demand based on your required logic of what links you want represented. In the example below, there is an in-memory db (this class is used as a stateful singleton class just for example) of books for which I add five books, with incrementing ids. When the request comes in, one or two links will be added to the returning BookStore. Depending on what id is being requested, we will add a "next" and/or a previous" link. The links will have rels that we refer to from our BookStore class.@Path("/books")public class BookResource { private final Map<Integer, Book> booksDB = Collections.synchronizedMap(new LinkedHashMap<Integer, Book>()); private final AtomicInteger idCounter = new AtomicInteger(); public BookResource() { Book book = new Book("Book One", "Author One"); booksDB.put(idCounter.incrementAndGet(), book); book = new Book("Book Two", "Author Two"); booksDB.put(idCounter.incrementAndGet(), book); book = new Book("Book Three", "Author Three"); booksDB.put(idCounter.incrementAndGet(), book); book = new Book("Book Four", "Author Four"); booksDB.put(idCounter.incrementAndGet(), book); book = new Book("Book Five", "Author Five"); booksDB.put(idCounter.incrementAndGet(), book); } @GET @Formatted @Path("/{id}") @Produces(MediaType.APPLICATION_XML) public BookStore getBook(@Context UriInfo uriInfo, @PathParam("id") int id) { List<Link> links = new ArrayList<>(); Collection<Book> books = new ArrayList<>(); UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); uriBuilder.path("books"); uriBuilder.path("{id}"); Book book = booksDB.get(id); if (book == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } synchronized(booksDB) { if (id + 1 <= booksDB.size()) { int next = id + 1; URI nextUri = uriBuilder.clone().build(next); Link link = Link.fromUri(nextUri).rel("next").type(MediaType.APPLICATION_XML).build(); links.add(link); } if (id - 1 > 0) { int previous = id - 1; URI nextUri = uriBuilder.clone().build(previous); Link link = Link.fromUri(nextUri).rel("previous").type(MediaType.APPLICATION_XML).build(); links.add(link); } } books.add(book); BookStore bookStore = new BookStore(); bookStore.setLinks(links); bookStore.setBooks(books); return bookStore; }}在测试用例中,我们要求提供第三本书,我们可以看到我们的内存数据库中有下一页和上一页书籍的链接。我们还在 BookStore 上调用 getNext()来检索数据库中的下一本书,结果将随附两个不同的链接。And in the test case, we request the third book, and we can see there are links for the "next" and "previous" books in our in-memory db. We also call getNext() on our BookStore to retrieve the next book in the db, and the result will come with two different links.public class BookResourceTest { private static Client client; @BeforeClass public static void setUpClass() { client = ClientBuilder.newClient(); } @AfterClass public static void tearDownClass() { client.close(); } @Test public void testBookResourceLinks() throws Exception { String BASE_URL = "http://localhost:8080/jaxrs-stackoverflow-book/rest/books/3"; WebTarget target = client.target(BASE_URL); String xmlResult = target.request().accept(MediaType.APPLICATION_XML).get(String.class); System.out.println(xmlResult); Unmarshaller unmarshaller = JAXBContext.newInstance(BookStore.class).createUnmarshaller(); BookStore bookStore = (BookStore)unmarshaller.unmarshal(new StringReader(xmlResult)); URI next = bookStore.getNext(); WebTarget nextTarget = client.target(next); String xmlNextResult = nextTarget.request().accept(MediaType.APPLICATION_XML).get(String.class); System.out.println(xmlNextResult); }}结果:<?xml version="1.0" encoding="UTF-8" standalone="yes"?><bookstore> <book author="Author Three" title="Book Three"/> <link href="http://localhost:8080/jaxrs-stackoverflow-book/rest/books/4" rel="next" type="application/xml"/> <link href="http://localhost:8080/jaxrs-stackoverflow-book/rest/books/2" rel="previous" type="application/xml"/></bookstore><?xml version="1.0" encoding="UTF-8" standalone="yes"?><bookstore> <book author="Author Four" title="Book Four"/> <link href="http://localhost:8080/jaxrs-stackoverflow-book/rest/books/5" rel="next" type="application/xml"/> <link href="http://localhost:8080/jaxrs-stackoverflow-book/rest/books/3" rel="previous" type="application/xml"/></bookstore> 仅供参考,我正在使用Resteasy 3.0.8使用Wildfly 8.1FYI, I'm using Resteasy 3.0.8 with Wildfly 8.1所以我尝试了参考指南示例,我无法重现您的问题。不确定你的完整环境,但这是我正在使用的So I tried out the reference guide example and I can't reproduce your problem. Not sure your complete environment, but here's what I'm using Wildfly 8.1 Resteasy 3.0 .8 Maven这是代码应用程序类@ApplicationPath("/rest")public class BookApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(Bookstore.class); return classes; }}资源等级@Path("/books")@Produces({"application/xml", "application/json"})public class Bookstore { @AddLinks @LinkResource(value = Book.class) @GET @Formatted public Collection<Book> getBooks() { List<Book> books = new ArrayList<>(); books.add(new Book("Book", "Author")); return books; }}预订课程@XmlRootElement@XmlAccessorType(XmlAccessType.NONE)public class Book { @XmlAttribute private String author; @XmlID @XmlAttribute private String title; @XmlElementRef private RESTServiceDiscovery rest; public Book() {} public Book(String title, String author) { this.title = title; this.author = author; }} pom.xml(也许你错过了一些依赖 - 注意下面的resteasy-client和resteasy-servlet-initializer仅用于测试)pom.xml (Maybe you are missing some dependencies - Note below resteasy-client and resteasy-servlet-initializer was just for testing)<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.underdogdevs.web</groupId> <artifactId>jaxrs-stackoverflow-user</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>jaxrs-stackoverflow-user</name> <properties> <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jaxb-provider</artifactId> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jaxrs</artifactId> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>jaxrs-api</artifactId> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-links</artifactId> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-servlet-initializer</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>jboss-javaee-7.0-with-resteasy</artifactId> <version>8.1.0.Final</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>jboss-javaee-7.0-with-tools</artifactId> <version>8.1.0.Final</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> <compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <phase>validate</phase> <goals> <goal>copy</goal> </goals> <configuration> <outputDirectory>${endorsed.dir}</outputDirectory> <silent>true</silent> <artifactItems> <artifactItem> <groupId>javax</groupId> <artifactId>javaee-endorsed-api</artifactId> <version>7.0</version> <type>jar</type> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> </plugins> </build></project> 在浏览器中正常工作Works fine in the browserpublic class BookTest { private static Client client; @BeforeClass public static void setUpClass() { client = ClientBuilder.newClient(); } @AfterClass public static void tearDownClass() { client.close(); } @Test public void testBookLink() { String BASE_URL = "http://localhost:8080/jaxrs-stackoverflow-user/rest/books"; WebTarget target = client.target(BASE_URL); String result = target.request() .accept(MediaType.APPLICATION_XML).get(String.class); System.out.println(result); }}结果Running jaxrs.book.test.BookTest<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection xmlns:atom="http://www.w3.org/2005/Atom"> <book author="Author" title="Book"> <atom:link rel="list" href="http://localhost:8080/jaxrs-stackoverflow-user/rest/books"/> </book></collection> 至于 Unclear StuffAs for your Unclear Stuff 用 @AddLinks 注释JAX-RS方法以表明你希望在响应实体中注入Atom链接。 Annotate the JAX-RS method with @AddLinks to indicate that you want Atom links injected in your response entity.这表示该方法将使用链接注入。This is to indicate that the method will make use of link injection. 使用 @LinkResource ,以便RESTEasy 知道要为哪些资源创建哪些链接。 Annotate the JAX-RS methods you want Atom links for with @LinkResource, so that RESTEasy knows which links to create for which resources.这允许您自定义链接是什么注入和实体。 8.2.4。指定哪些JAX-RS方法与哪些资源绑定更深入。This allows you to customize what links are injected and for what entities. 8.2.4. Specifying which JAX-RS methods are tied to which resources goes more in depth. 将RESTServiceDiscovery字段添加到资源类中你想要注入Atom链接。 Add RESTServiceDiscovery fields to the resource classes where you want Atom links injected. inject意味着框架会为你实例化它,所以你永远不必自己明确地做(正如你试图做的那样)。也许对依赖注入和控制反转(IoC)做一些研究"injected" means the framework will instantiate it for you, so you never have to explicitly do it yourself (as you attempted to do). Maybe do some research on dependency injection and Inversion of Control (IoC) 祝你好运。希望这一切都有所帮助。 这篇关于通过JAXB将链接插入RESTEasy XML结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 07-29 10:32