One other option (my preferred way), similar to your option C.

Think in terms of services and messages, rather than objects, classes
and methods. Get away from the "services as a way of doing remote Java
method invocation" mindset. Design your services WSDL-first (if
possible) for all the good reasons discussed here:

http://static.springframework.org/spring-ws/sites/1.5/reference/html/why-contract-first.html

As for your specific example, it depends on the requirements of your
application, but you could provide four operations:

GetAuthorByID

GetBookByID

GetAuthorWithBooksByID

GetBookWithAuthorsByID

The first two just return an author or book element respectively, but
the last two have the books for that author, or authors for that book,
nested within.

If it would make things smoother, you can also provide:

GetAuthorsByBookID

GetBooksByAuthorID

These can remove the redundancy when the client already has the book,
and wants the authors, or vice versa. But only write these if you
actually need them.

Design operations that reflect your actual business logic, don't worry
about things like cyclic dependencies, and maybe they won't be an
issue in practice. All it might mean is a little more 'glue' code to
mediate between your web services and your persistent JPA objects.

This also means you'll end up with portable and interoperable WSDLs,
it decouples your service contract from any one programming language
or toolkit, and allows the WSDL to will remain stable even if the
server-side data model has to change.

Andrew.

2009/3/2 geirgp <gei...@gmail.com>:
>
> Now, this is more a Web Service design issue than a CXF issue, but I am
> wondering how CXF/Java users solve/work around it.
>
> The WS definition is limited compared to how you can model data in an OO
> language. A classic example is bidirectional relationships, widely used in
> JPA/Hibernate applications, which would lead to cyclic references and a hard
> crash if used with CXF. I've written my thoughts below, but have no clear
> idea about what is the best approach on how to work around this issue. What
> are your experiences/best practices?
>
> I will use the Author-Book model as an example to express my thoughts:
>
> public class Author{
>   private Long id;
>   private String name;
>   private Collection<Book> books;
> }
>
> public class Book{
>   private Long id;
>   private String title;
>   private Author author;
> }
>
> In its current form this model will cause a cyclic reference error when used
> with CXF because Author holds a collection of Books which refers back to the
> Author. I have come up with 3 strategies to work around this issue and
> "CXF-enable" my service:
>
> A)
> Modify domain model to have no cyclic dependencies by removing either
> Book.author OR Author.books. Example:
>
> public class Author{
>   private Long id;
>   private String name;
>   private Collection<Book> books;
> }
>
> public class Book{
>   private Long id;
>   private String title;
>
> }
> Pros:
> * Model can still be traversed (one direction) without making another call
> to the service.
> cons:
> * Model can only be traversed one way (Author->Books). When client has a
> Book, he must make another call to the service to get the Author. More
> complexity and more costly in terms of performance
> * I have to change my server-side business code which depends on traversing
> objects, they can no longer access book.getAuthor(). Instead I will have to
> introduce an extra dao-call, AuthorDao.findByBookId(..). This is not good in
> terms of both complexity and performance.
>
> B)
> Another possible solution is to introduce a layer between my DAO and
> WebService implementation which nulls out potentional cyclic references,
> example:
>
> @WebService
> public class LibraryService {
>  private AuthorDao authorDao;
>  private BookDao bookDao;
>
>  public Author findAuthorById(Long id) {
>  Author author = authorDao.find( id );
>  for( Book book : author.getBooks() ) {
>   book.setAuthor( null );
>  }
>  return author;
>  }
>
>  public Book findBookById( Long id ) {
>  Book book = bookDao.find( id );
>  book.getAuthor().setBooks( null );
>  return book ;
>  }
> }
>
> Pros:
> * I can keep my Domain model and traverse both ways (serverside)
> * Model can be traversed all ways, but only one way at a time (if that makes
> sense). See cons for details about this
>
>
> Cons:
> * Inconsitency in model which cannot be traversed both ways on client side.
> Books belong to an Author yet Book.author is null.
> ** When retrieveing a book, you can traverse the book and find its author,
> but not go back and find the author's books.
> ** When retrieving an author, you can traverse the author and find her
> books, but not go back and find the books' author.
> * SOAP is only ONE of the remoting protocols used for exposing my web
> services - Spring HTTP Invoker, which is capable of handling cyclic
> references, is another one. I will have to maintain two service
> implementations, one for CXF/SOAP where Book.author is nulled ouit, and one
> for SPRING where Book.author is kept.
>
> C)
> Create a WS-specific domain model and introduce mapping between this model
> and my "proper" domain model:
>
> public class AuthorWS{
>   private Long id;
>   private String name;
>   private Collection<Long> bookIds;
> }
>
> public class BookWS{
>   private Long id;
>   private String title;
>   private Long authorId;
> }
>
>
> Pros:
> * I can keep my domain model and traverse the model at server-side.
> * Data returned from my Web Service will be consistent: no references are
> nulled out.
>
> Cons:
> * Data returned from Web Service is "flat" instead of "good" OO-model: When
> I have found a Book, i have to make another call to get the Author (and vice
> versa). This will affect both client-code design and performance.
> * Complexity at serverside: introduces extra layer which handles mapping.
>
> D)
> What have I missed? What is your best practice?
> --
> View this message in context: 
> http://www.nabble.com/OO-%3C-%3E-WS-paradigm-mismatch-tp22286364p22286364.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>
>



-- 
:: http://biotext.org.uk/ ::

Reply via email to