Ivar, I've created a provider that uses JAXB to marshall/unmarshall my book
:
*_at_Provider*
public class BookParamConverterProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(Class<T> type, Type
genericType, Annotation[] annotations) {
if (type.equals(Book.class)) {
return (ParamConverter<T>) new BookParamConverter();
} else {
return null;
}
}
private static class BookParamConverter implements ParamConverter<Book>
{
@Override
public Book *fromString*(String value) {
try {
JAXBContext ctx = JAXBContext.newInstance(Book.class);
Unmarshaller m = ctx.createUnmarshaller();
Book book = (Book) m.unmarshal(new StringReader(value));
return book;
} catch (JAXBException e) {
return null;
}
}
@Override
public String *toString*(Book value) {
try {
StringWriter writer = new StringWriter();
JAXBContext ctx = JAXBContext.newInstance(Book.class);
Marshaller m = ctx.createMarshaller();
m.marshal(this, writer);
return writer.toString();
} catch (JAXBException e) {
return null;
}
}
}
}
But when I invoke the resource with no toXML() method (got rid of it into
my bean), just the bean itself (example) :
Book example = new Book();
example.setTitle("Java");
Response response = client.target(URL + "/books").path("/query")
.queryParam("example", *example*)
.request(MediaType.APPLICATION_XML)
.get();
I get a 404. I registered the provider (as follow) but still get a 404.
Any idea ? What am I doing wrong ?
Thanks
Response response = client.target(URL + "/books").path("/query")
.queryParam("example", example)
*.register(BookParamConverterProvider.class)*
.request(MediaType.APPLICATION_XML)
.get();
And the application config class :
@ApplicationPath("/rest")
public class ApplicationConfig extends Application {
private final Set<Class<?>> classes;
public ApplicationConfig() {
HashSet<Class<?>> c = new HashSet<>();
c.add(BookEndpoint.class);
*c.add(BookParamConverterProvider.class);*
classes = Collections.unmodifiableSet(c);
}
public Set<Class<?>> getClasses() { return classes;
}
}
2013/10/22 Ivar <ivarconr_at_gmail.com>
> Hi,
>
> What you could do is have a a registered implementation of
> javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that returns a
> javax.ws.rs.ext.ParamConverter instance capable of a "from string"
> conversion for the Book type.
>
> Ivar Østhus
>
>
>
> Med vennlig hilsen,
>
> Ivar Conradi Østhus
> 920 43 382
> ivarconr_at_gmail.com
>
>
> On 22 October 2013 15:28, Antonio Goncalves <antonio.mailing_at_gmail.com>wrote:
>
>> Hi all,
>>
>> I'm using a very manual approach to solve this problem and I would like
>> to share it with you in case you have a better idea. Basically my resource
>> doesn't do much, it just uses a @QueryParam to get the XML and JPA to do a
>> QBE :
>>
>> @GET
>> @Path("*/query*")
>> @Produces("application/xml")
>> public Response findByQBE(*_at_QueryParam("example")* *Book* example) {
>>
>> CriteriaBuilder builder = em.getCriteriaBuilder();
>> CriteriaQuery<Book> criteria = builder.createQuery(Book.class);
>> // ...
>> // query by example
>> return Response.ok(books).build();
>> }
>>
>>
>> The manual work that I do is in the Book entity. Basically I give it a
>> constructor with a String (needed by JAX-RS) to be able to unmarshall the
>> XML into the bean itself, and I create a toXML() method that marshalls the
>> bean into XML :
>>
>> @Entity
>> *_at_XmlRootElement*
>> public class Book implements Serializable {
>>
>> @Id @GeneratedValue
>> private String isbn;
>> private String title;
>> private String description;
>> // ... other attributes
>>
>> public Book() {
>> }
>>
>> public *Book(String xml)* throws JAXBException {
>> // Uses JAXB to unmarshall the XML string into the bean itself
>> JAXBContext ctx = JAXBContext.newInstance(Book.class);
>> Unmarshaller m = ctx.createUnmarshaller();
>> Book book = (Book) m.*unmarshal*(new StringReader(xml));
>> this.isbn = book.getIsbn();
>> this.title = book.getTitle();
>> this.description = book.getDescription();
>> this.nbOfPages = book.getNbOfPages();
>> this.publisher = book.getPublisher();
>> }
>>
>> public String *toXML()* throws JAXBException {
>> // Uses JAXB to marshall the bean into an XML string
>> StringWriter writer = new StringWriter();
>> JAXBContext ctx = JAXBContext.newInstance(Book.class);
>> Marshaller m = ctx.createMarshaller();
>> m.*marshal*(this, writer);
>> return writer.toString();
>> }
>>
>> // ... getters & setters
>> }
>>
>> Then, to invoke my resource with the Client API, I just call the toXML()
>> method as follow :
>>
>> Book example = new Book();
>> example.setTitle("Java");
>> Response response = client.target(URL + "/books").path("/query")
>> .queryParam("example", *example.toXML()*)
>> .request(MediaType.APPLICATION_XML)
>> .get();
>>
>> This way I invoke the resource with a request that looks like what I want
>> :
>>
>> /rest/books/*query/example=<book><title>Java</title></book>*
>>
>>
>> So it does work except there is many manual code that, in my mind, could
>> be automatised. Am I wrong ? Do you have a better idea ? In this case I
>> suppose a provider would make sense but I already use JAXB and XML so it
>> feels weird to do the job a second time.
>>
>> Thanks for you thoughts
>>
>> Antonio
>>
>>
>> 2013/10/22 Antonio Goncalves <antonio.mailing_at_gmail.com>
>>
>>> Hi all,
>>>
>>> I need to implement a query by example service and be able to consume it
>>> with the new client API.
>>>
>>> The idea is that I have a Book entity with a JAXB annotation :
>>>
>>> @Entity
>>> @XmlRootElement
>>> public class Book implements Serializable {
>>>
>>> @Id @GeneratedValue
>>> private Long id = null;
>>>
>>> private String isbn;
>>> private String title;
>>> private String description;
>>> }
>>>
>>>
>>> I now need a service that would be able to receive an 'example' of the
>>> Book in XML format. So if the service receives :
>>>
>>> <book><isbn>1234</isbn></book>
>>>
>>> It will return all the books with an ISBN like '1234. If the service
>>> receives :
>>>
>>> <book><isbn>1234</isbn><title>Java</title><description>Best
>>> book</description></book>
>>>
>>> Il will return all the books with an ISBN like '1234' AND a title like
>>> 'Java' AND a description like 'Best Book'. As you can see, the query string
>>> depends on which attributes of the entity are set. So I was thinking of
>>> having a URI that would look like :
>>>
>>> /rest/books/*query*=<book><isbn>1234</isbn></book>
>>> /rest/books/*query*=<book><isbn>1234</isbn><title>Java</title><description>Best
>>> book</description></book>
>>>
>>> So I assume that the resource would then look like :
>>>
>>> @GET
>>> public Response findByQBE(@QueryParam("*query*") Book example) {
>>> ...
>>> }
>>>
>>> And the client API
>>>
>>> Book *example* = new Book();
>>> example.setTitle("Java");
>>> client.target(URL + "/books").path("/qbe").queryParam("*query*", *
>>> example*).request(MediaType.APPLICATION_XML).get();
>>>
>>> But that doesn't work (I get a 404).
>>>
>>> I feel I don't need to write a provider to marshall the POJO into an XML
>>> String. So I think I'm doing something wrong here.
>>>
>>> Any idea
>>>
>>> Thanks
>>>
>>> --
>>> Antonio Goncalves
>>> Software architect and Java Champion
>>>
>>> Web site <http://www.antoniogoncalves.org/> | Twitter<http://twitter.com/agoncal>
>>> | LinkedIn <http://www.linkedin.com/in/agoncal> | Paris JUG<http://www.parisjug.org/>
>>> | Devoxx France <http://www.devoxx.fr/>
>>>
>>
>>
>>
>> --
>> Antonio Goncalves
>> Software architect and Java Champion
>>
>> Web site <http://www.antoniogoncalves.org/> | Twitter<http://twitter.com/agoncal>
>> | LinkedIn <http://www.linkedin.com/in/agoncal> | Paris JUG<http://www.parisjug.org/>
>> | Devoxx France <http://www.devoxx.fr/>
>>
>
>
--
Antonio Goncalves
Software architect and Java Champion
Web site <http://www.antoniogoncalves.org/> |
Twitter<http://twitter.com/agoncal>
| LinkedIn <http://www.linkedin.com/in/agoncal> | Paris
JUG<http://www.parisjug.org/>
| Devoxx France <http://www.devoxx.fr/>