Rob*_*ert 6 java jax-rs jaxb java-ee resteasy
我想通过RESTeasy/JAXB将链接插入XML .我试图使用我的代码的文档,但这不起作用,所以我只是在文档中编写给定的示例:它仍然不起作用,我不知道为什么.
要在我的JBoss RESTEasy API中实现HATEOAS原则,我必须在我的JAXB XML结果中插入链接,以便客户端可以浏览API.
我现在正试图了解如何做到这一点,但我不确定 文档是否充满错误,或者我只是无法理解示例和解释:
据我所知,你必须使用@AddLinks声明结果应该插入链接.然后我必须再次冗余地(!?)@LinkResource和" 有时 "指定URI构建过程应该来自哪个类(例如@LinkResource(value = car.class)).然后我必须RESTServiceDiscovery在实体类中添加一个,用@XmlElementRef... 注释它但是在RESTServiceDiscovery声明(!?)后,示例中根本没有使用它.
我真的很困惑如何使用所有这些,但当然我自己尝试了很多代码,让它工作.
以下代码就像文档示例:
BookController.java
import 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");
};
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在调用GET上books或book/1引发此错误:
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 IllegalAnnotationExceptions
XmlElementRef points to a non-existent class.
Run Code Online (Sandbox Code Playgroud)
我不知道如何可以工作,所以我试着用下面的代码中手动添加的URI 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");
}
Run Code Online (Sandbox Code Playgroud)
但这仍然会引发同样的错误.
Pau*_*tha 11
我对链接注入不太熟悉,但添加链接的一种简单方法是将javax.ws.rs.core.Links嵌入到JAXB实体类中.它带有一个内置的XmlAdapter,Link.JaxbAdapter它允许LinkJAXB 对该类型进行编组和解组.举个例子,你有一个BookStore包含一个集合的类Books.它也可以Link用来控制导航案例.
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
该Book班只是一个普通的根元素JAXB类
@XmlRootElement
public class Book {
@XmlAttribute
private String author;
@XmlAttribute
private String title;
public Book() {}
public Book(String title, String author) {
this.title = title;
this.author = author;
}
}
Run Code Online (Sandbox Code Playgroud)
在BookResource课堂上,我们基本上可以根据您想要表示的链接所需的逻辑按需添加链接.在下面的示例中,存在的用于我添加五本书,与递增IDS书籍内存中的分贝(这类被用作有状态单例类只是例子).当请求进入时,将返回一个或两个链接BookStore.根据请求的ID,我们将添加"下一个"和/或之前的"链接.链接将包含rel我们在BookStore课堂上引用的内容.
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
在测试用例中,我们请求第三本书,我们可以看到内存数据库中有"下一页"和"上一页"书籍的链接.我们还要求getNext()我们BookStore检索数据库中的下一本书,结果将带有两个不同的链接.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
<?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>
Run Code Online (Sandbox Code Playgroud)
仅供参考,我正在使用Resteasy 3.0.8和Wildfly 8.1
所以我尝试了参考指南示例,我无法重现您的问题.不确定你的完整环境,但这是我正在使用的
这是代码
应用类
@ApplicationPath("/rest")
public class BookApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(Bookstore.class);
return classes;
}
}
Run Code Online (Sandbox Code Playgroud)
资源类
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
预订课程
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
pom.xml(也许你缺少一些依赖项 - 注意下面的resteasy-client和resteasy-servlet-initializer仅用于测试)
<?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>
Run Code Online (Sandbox Code Playgroud)

public 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);
}
}
Run Code Online (Sandbox Code Playgroud)
结果
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>
Run Code Online (Sandbox Code Playgroud)
使用JAX-RS方法注释,
@AddLinks以指示您希望在响应实体中注入Atom链接.
这是为了表明该方法将使用链接注入.
注释您希望Atom链接的JAX-RS方法
@LinkResource,以便RESTEasy知道要为哪些资源创建哪些链接.
这允许您自定义注入的链接和实体.8.2.4.指定哪些JAX-RS方法与哪些资源的关联更深入.
将RESTServiceDiscovery字段添加到您希望注入Atom链接的资源类中.
"注入"意味着框架将为您实例化,因此您永远不必自己明确地执行此操作(正如您尝试的那样).也许对依赖注入和控制反转(IoC)进行一些研究
祝好运.希望这一切都有帮助.
| 归档时间: |
|
| 查看次数: |
5032 次 |
| 最近记录: |