cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tom <t...@tbee.org>
Subject Re: Inheriting methods
Date Fri, 15 May 2009 20:27:59 GMT
This is available in a nightly build?




Sergey Beryozkin wrote:
> Hi Tom
>
> I believe it has to work now, just applied some fixes.
> Note that the (JAXRS) method inheritance used to work anyway (from 
> abstract classes or interfaces), it was the fact that you introduced 
> type variables that did 'upset' the runtime a bit...
>
> So you should be able to do either on interface or on abstract class :
>
> class AbstractResource<T, E> {
>
>    @POST
>    E post(T) {};
> }
>
>
> By the way, I also fixed the super fields injection issue, so you can 
> now get rid of the SevletContext method setter if you wish...
> It all has to be in snapshots starting from tomorrow - please 
> experiment with the inheritance fixes whenever you get a chance and 
> let me know how it all works,
>
> There could be some generics subtleties there which are still not 
> supported - will fix if some problems are discovered
>
> Cheers, Sergey
>
>
> ----- Original Message ----- From: "Tom" <tbee@tbee.org>
> To: <users@cxf.apache.org>
> Sent: Thursday, May 14, 2009 2:14 PM
> Subject: Re: Inheriting methods
>
>
>> Attached my UserService classes. If I take out the two methods in the
>> UserServiceImpl and uncomment the annotions in the AbstractServiceImpl I
>> get the exception. You can maybe try this code as a basis for your test
>> and replace the FEST reflection code with test code. If you like I can
>> provide some test code for the methods.
>>
>> What also may be a factor, I do not know, is that my User entity is a
>> three layer inheritance entity (custom class -> generated class ->
>> generic bean stuff class). But as said; it is marshalled by JAXB, all
>> works fine, except when introducing this abstract service thing.
>>
>> Tom
>>
>>
>>
>> Sergey Beryozkin wrote:
>>> Hi Tom
>>> I added this test code :
>>>
>>> public class AbstractEntity<T> {
>>>  private T entity;
>>>  @POST
>>>  public void postEntity(T object) {
>>>     entity = object;
>>>  }
>>>
>>>  public T getEntity() {
>>>    return entity;
>>>  }
>>> }
>>>
>>> @Path("/books")
>>> public class BookEntity extends AbstractEntity<Book> {
>>> }
>>>
>>> AbstractEntity#postEntity is being resolved for requests like "POST
>>> /books <Books/>" in my test and a JAXB provider is invoked (I see a
>>> diff kind of issue there though), I'm setting text/xml as content type.
>>> What am I missing ? I've seen your code implementing UserService -
>>> does it have JAX-RS methods ? I'm also seen in your post
>>> Cheers, Sergey
>>>
>>>
>>>
>>>> Hey Sergey,
>>>>
>>>> I do not know what the reason is, all I know is that if I have:
>>>>
>>>>    @POST public void add(User user) {...}
>>>>
>>>> In the regular class, it works, but if I move the code to the
>>>> abstract class and make it generic, like so:
>>>>
>>>>    @POST public void add(T user) {...}
>>>>
>>>> then I get the exception. But it works ok for @GET list(), or @GET
>>>> find(long id).
>>>>
>>>> Tom
>>>>
>>>> PS: Please note my typo in the initial post that the abstract class
>>>> does not know "User" but only the generic "T".
>>>>
>>>>
>>>>
>>>>
>>>> Sergey Beryozkin wrote:
>>>>> Hi,
>>>>>
>>>>> So just to confirm, for the purpose of writing a test,
>>>>>
>>>>> @Path(...)
>>>>> @Produces(...)
>>>>> UserServiceImpl extends AbstractServiceImpl<User>
>>>>> implements UserService
>>>>> {
>>>>> }
>>>>>
>>>>>
>>>>> abstract class AbstractServiceImpl<T> {
>>>>> {
>>>>>    @POST
>>>>>    public void add(User user) {...// reflection ...//}
>>>>> }
>>>>>
>>>>> can not be matched with 'User' add parameter being confused for
>>>>> Object ?
>>>>> If no then please correct me...
>>>>> I'll do a test shortly
>>>>>
>>>>> Cheers, Sergey
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> ----- Original Message ----- From: "Tom" <tbee@tbee.org>
>>>>> To: <users@cxf.apache.org>
>>>>> Sent: Thursday, May 14, 2009 10:52 AM
>>>>> Subject: Inheriting methods
>>>>>
>>>>>
>>>>>> I have to implement basic CRUD operations on a serious number of
>>>>>> Entities. The to-be-executed code is identical for all classes,
>>>>>> except that different DAO implementating classes are involved. So
I
>>>>>> decided to go for reflection, so instead of:
>>>>>>
>>>>>> /@Path(...)
>>>>>> @Produces(...)
>>>>>> implements UserService
>>>>>> UserServiceImpl
>>>>>> {
>>>>>>    @GET
>>>>>>    public void list() {... same code over and over again... }
>>>>>>
>>>>>>    @POST
>>>>>>    public void add(User user) {... //same code over and over
>>>>>> again... //}
>>>>>> }
>>>>>> /
>>>>>>
>>>>>> I have
>>>>>>
>>>>>>
>>>>>> /@Path(...)
>>>>>> @Produces(...)
>>>>>> UserServiceImpl extends AbstractServiceImpl<User>
>>>>>> implements UserService
>>>>>> {
>>>>>> }
>>>>>>
>>>>>>
>>>>>> abstract AbstractServiceImpl<T>
>>>>>> {
>>>>>>    @GET
>>>>>>    public void list() {... reflection ...}
>>>>>>
>>>>>>    @POST
>>>>>>    public void add(User user) {...// reflection ...//}
>>>>>> }
>>>>>> /
>>>>>>
>>>>>> This works fine for REST-GET but not for REST-POST, there I get a
>>>>>> "No message body reader found for request class : Object,
>>>>>> ContentType : text/xml". This most definitely has to do with the
>>>>>> resolving of the @POST, because if I add the code below the the
>>>>>> UserServiceImpl, then it all works ok.
>>>>>>
>>>>>> /    @POST public void add(User user) { super.add(user); }
>>>>>>
>>>>>> /Any suggestions on why?
>>>>>>
>>>>>> Tom
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>>
>>
>>
>
>
> -------------------------------------------------------------------------------- 
>
>
>
>> /*
>> * Copyright: (c) Innovation Investments
>> * Version:   $Revision: 1.1 $
>> * Modified:  $Date: 2009/05/14 12:02:05 $
>> * By:        $Author: toeukps $
>> */
>> package nl.knowledgeplaza.profiler.services;
>>
>>
>> /**
>> *
>> * @author User
>> *
>> */
>> @javax.jws.WebService
>> public interface AbstractService<T, Ts>
>> {
>> /**
>> *
>> * @return Users object containing a collection of User
>> * @exception REST: sends a 500 on any error
>> */
>> public Ts list();
>>
>> /**
>> *
>> * @param id
>> * @return User object
>> * @exception REST: sends a 500 on any error
>> */
>> public T find(long id);
>>
>> /**
>> * @param entity
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void add(T entity);
>>
>> /**
>> *
>> * @param id
>> * @param entity
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void update(long id, T entity);
>>
>> /**
>> *
>> * @param id
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void delete(long id);
>> }
>>
>
>
> -------------------------------------------------------------------------------- 
>
>
>
>> /*
>> * Copyright: (C) Innovation Investments
>> * Version:   $Revision: 1.3 $
>> * Modified:  $Date: 2009/05/14 12:02:05 $
>> * By: $Author: toeukps $
>> *
>> * CXF http://cwiki.apache.org/CXF20DOC/index.html
>> *     
>> http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Dealingwithcontexts
>> *     JAX-RS 
>> http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features
>> * JAXB https://jaxb.dev.java.net/tutorial/
>> */
>> package nl.knowledgeplaza.profiler.services;
>>
>> import java.math.BigInteger;
>> import java.util.List;
>>
>> import javax.persistence.EntityManager;
>>
>> import org.fest.reflect.reference.TypeRef;
>> import org.tbee.util.ExceptionUtil;
>> import org.tbee.util.jpa.EntityManagerFinder;
>>
>> /**
>> *
>> * @author toeu
>> *
>> */
>> abstract public class AbstractServiceImpl<T, Ts>
>> {
>> // logger (http://www.slf4j.org/faq.html#declared_static)
>> transient final protected org.slf4j.Logger slf4j = 
>> org.slf4j.LoggerFactory.getLogger(this.getClass());
>>
>> // 
>> =======================================================================
>> // CONSTRUCTOR
>>
>> /**
>> *
>> */
>> public AbstractServiceImpl(Class entityClass, Class collectionClass)
>> {
>> iEntityClass = entityClass;
>> iCollectionClass = collectionClass;
>> }
>> private Class iEntityClass = null;
>> private Class iCollectionClass = null;
>>
>> // 
>> =======================================================================
>> // SERVICES
>>
>> /**
>> * list all
>> */
>> @javax.ws.rs.GET
>> public Ts list()
>> {
>> try
>> {
>> if (slf4j.isDebugEnabled()) slf4j.debug("list {}", 
>> iEntityClass.getSimpleName());
>>
>> // find all
>> // example: List<T> lList = Entity.findAll();
>> List<T> lList = 
>> org.fest.reflect.core.Reflection.staticMethod("findAll") // 
>> http://docs.codehaus.org/display/FEST/Invoking+Static+Methods
>>                                                 .withReturnType( new 
>> TypeRef<List<T>>(){} ) // 
>> http://docs.codehaus.org/display/FEST/Overcoming+Type+Erasure
>>                                                 .in(iEntityClass)
>>                                                 .invoke()
>>                                                 ;
>> if (slf4j.isDebugEnabled()) slf4j.debug("list {} size={}", 
>> iEntityClass.getSimpleName(), lList.size());
>>
>> // create a collection so JAXB knows what to do
>> // example: Entitys lTs = new Entitys(lList);
>> Ts lTs = (Ts)org.fest.reflect.core.Reflection.constructor() // 
>> http://docs.codehaus.org/display/FEST/Invoking+Constructors
>>                                              
>> .withParameterTypes(java.util.Collection.class) // Due to type 
>> erasure, there can only be one constructor with a List as the 
>> parameter type 
>> (http://java.sun.com/docs/books/tutorial/java/generics/erasure.html)
>>                                              .in(iCollectionClass) // 
>> TODO: why is TypeRef not possible here?
>>                                              .newInstance(lList)
>>                                              ;
>>
>> // done
>> return lTs;
>> }
>> catch (RuntimeException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw e;
>> }
>> }
>>
>> /**
>> * find one
>> */
>> @javax.ws.rs.GET
>> @javax.ws.rs.Path("/{id}")
>> public T find(@javax.ws.rs.PathParam("id") long id)
>> {
>> try
>> {
>> if (slf4j.isDebugEnabled()) slf4j.debug("find {}={}", 
>> iEntityClass.getSimpleName(), id);
>> // example: Entity lEntity = Entity.findByPK( BigInteger.valueOf(id) );
>> T lT = (T)org.fest.reflect.core.Reflection.staticMethod("findByPK") 
>> // http://docs.codehaus.org/display/FEST/Invoking+Static+Methods
>>                                                   .withReturnType( 
>> iEntityClass ) //  why does this not work: new TypeRef<T>(){} // 
>> http://docs.codehaus.org/display/FEST/Overcoming+Type+Erasure
>>                                                   
>> .withParameterTypes( BigInteger.class )
>>                                                   .in(iEntityClass)
>>                                                   .invoke( 
>> BigInteger.valueOf(id) )
>>                                                   ;
>> if (slf4j.isDebugEnabled()) slf4j.debug("find {}={}", 
>> iEntityClass.getSimpleName(), lT);
>> return lT;
>> }
>> catch (RuntimeException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw e;
>> }
>> }
>>
>> /**
>> * Insert new entity
>> * @param entity
>> */
>> // we get an exception if this code is placed here and not in the 
>> inheriting class
>> // @javax.ws.rs.POST
>> public void add(T entity)
>> {
>> try
>> {
>> if (slf4j.isDebugEnabled()) slf4j.debug("add {}={}", 
>> iEntityClass.getSimpleName(), entity);
>> EntityManager lEntityManager = EntityManagerFinder.find();
>> try
>> {
>> lEntityManager.getTransaction().begin();
>> lEntityManager.persist(entity);
>> lEntityManager.getTransaction().commit();
>> }
>> catch (org.eclipse.persistence.exceptions.DatabaseException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw new RuntimeException(e);
>> }
>> finally
>> {
>> // rollback if still active
>> if (lEntityManager != null && 
>> lEntityManager.getTransaction().isActive()) 
>> lEntityManager.getTransaction().rollback();
>> }
>> }
>> catch (RuntimeException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw e;
>> }
>> }
>>
>> /**
>> * Update an entity
>> * @param id
>> * @param entity
>> */
>> // we get an exception if this code is placed here and not in the 
>> inheriting class
>> // @javax.ws.rs.PUT
>> // @javax.ws.rs.Path("/{id}")
>> // public void update(@javax.ws.rs.PathParam("id") long id, T entity)
>> public void update(long id, T entity)
>> {
>> try
>> {
>> if (slf4j.isDebugEnabled()) slf4j.debug("update {} id={}", 
>> iEntityClass, id);
>> EntityManager lEntityManager = EntityManagerFinder.find();
>> try
>> {
>> lEntityManager.getTransaction().begin();
>> // example: Entity lEntity = Entity.findByPK( BigInteger.valueOf(id) );
>> T lT = (T)org.fest.reflect.core.Reflection.staticMethod("findByPK") 
>> // http://docs.codehaus.org/display/FEST/Invoking+Static+Methods
>>                                                          
>> .withReturnType( iEntityClass ) //  why does this not work: new 
>> TypeRef<T>(){}     // 
>> http://docs.codehaus.org/display/FEST/Overcoming+Type+Erasure
>>                                                          
>> .withParameterTypes( BigInteger.class )
>>                                                          
>> .in(iEntityClass)
>>                                                          .invoke( 
>> BigInteger.valueOf(id) )
>>                                                          ;
>> if (lT == null) throw new 
>> IllegalArgumentException(iEntityClass.getSimpleName() + " " + id + " 
>> does not exist");
>> // example: Entity.shallowCopy(entity, lEntity);
>> org.fest.reflect.core.Reflection.staticMethod("shallowCopy") // 
>> http://docs.codehaus.org/display/FEST/Invoking+Static+Methods
>>                                                .withParameterTypes( 
>> iEntityClass, iEntityClass )
>>                                                .in(iEntityClass)
>>                                                .invoke( entity, lT )
>>                                                ;
>> lEntityManager.getTransaction().commit();
>> }
>> finally
>> {
>> // rollback if still active
>> if (lEntityManager != null && 
>> lEntityManager.getTransaction().isActive()) 
>> lEntityManager.getTransaction().rollback();
>> }
>> }
>> catch (RuntimeException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw e;
>> }
>> }
>>
>> /**
>> * Delete an entity
>> * @param id
>> */
>> @javax.ws.rs.DELETE
>> @javax.ws.rs.Path("/{id}")
>> public void delete(@javax.ws.rs.PathParam("id") long id)
>> {
>> try
>> {
>> if (slf4j.isDebugEnabled()) slf4j.debug("delete, id={}", id);
>> EntityManager lEntityManager = EntityManagerFinder.find();
>> try
>> {
>> lEntityManager.getTransaction().begin();
>> // example: Entity lEntity = Entity.findByPK( BigInteger.valueOf(id) );
>> T lT = (T)org.fest.reflect.core.Reflection.staticMethod("findByPK") 
>> // http://docs.codehaus.org/display/FEST/Invoking+Static+Methods
>>                                                          
>> .withReturnType( iEntityClass ) //  why does this not work: new 
>> TypeRef<T>(){}     // 
>> http://docs.codehaus.org/display/FEST/Overcoming+Type+Erasure
>>                                                          
>> .withParameterTypes( BigInteger.class )
>>                                                          
>> .in(iEntityClass)
>>                                                          .invoke( 
>> BigInteger.valueOf(id) )
>>                                                          ;
>> if (lT == null) throw new 
>> IllegalArgumentException(iEntityClass.getSimpleName() + " " + id + " 
>> does not exist");
>> lEntityManager.remove(lT);
>> lEntityManager.getTransaction().commit();
>> }
>> finally
>> {
>> // rollback if still active
>> if (lEntityManager != null && 
>> lEntityManager.getTransaction().isActive()) 
>> lEntityManager.getTransaction().rollback();
>> }
>> }
>> catch (RuntimeException e)
>> {
>> slf4j.error(ExceptionUtil.describe(e), e);
>> throw e;
>> }
>> }
>>
>> // 
>> =======================================================================
>> // SESSION
>>
>> // Moving this code to this class result in that SOAP works, but REST 
>> returns NULL
>>
>> // // Get context for SOAP and REST
>> // // SOAP context: 
>> http://cwiki.apache.org/CXF20DOC/webservicecontext.html
>> // @javax.annotation.Resource private javax.xml.ws.WebServiceContext 
>> iSoapWebServiceContext;
>> // // REST context: 
>> http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Contextannotations
>> // @javax.ws.rs.core.Context private javax.servlet.ServletContext 
>> iRestServletContext;
>> // //@javax.annotation.Resource private 
>> org.apache.cxf.jaxrs.ext.MessageContext iRestMessageContext;
>> // // combining SOAP and REST: 
>> http://cwiki.apache.org/CXF20DOC/jax-rs.html#JAX-RS-Dealingwithcontexts
>> //
>> // protected javax.servlet.ServletContext getServletContext()
>> // throws javax.ws.rs.WebApplicationException
>> // {
>> // if (iSoapWebServiceContext != null)
>> // {
>> // // soap invocation
>> // return 
>> (javax.servlet.ServletContext)iSoapWebServiceContext.getMessageContext().get(javax.xml.ws.handler.MessageContext.SERVLET_CONTEXT);

>>
>> // }
>> // else
>> // {
>> // // http-only jaxrs one
>> // return 
>> iRestServletContext;//(javax.servlet.ServletContext)iRestMessageContext.get(MessageContext.SERVLET_CONTEXT);

>>
>> // }
>> // }
>>
>> }
>>
>
>
> -------------------------------------------------------------------------------- 
>
>
>
>> /*
>> * Copyright: (c) Innovation Investments
>> * Version:   $Revision: 1.3 $
>> * Modified:  $Date: 2009/05/14 12:02:05 $
>> * By:        $Author: toeukps $
>> */
>> package nl.knowledgeplaza.profiler.services;
>>
>> import nl.knowledgeplaza.profiler.engine.model.User;
>> import nl.knowledgeplaza.profiler.services.support.Users;
>>
>> /**
>> *
>> * @author User
>> *
>> */
>> @javax.jws.WebService
>> public interface UserService// SOAP via CXF throws an exception: 
>> extends AbstractService<User, Users>
>> {
>> /**
>> *
>> * @return Users object containing a collection of User
>> * @exception REST: sends a 500 on any error
>> */
>> public Users list();
>>
>> /**
>> *
>> * @param id
>> * @return User object
>> * @exception REST: sends a 500 on any error
>> */
>> public User find(long id);
>>
>> /**
>> * @param user
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void add(User user);
>>
>> /**
>> *
>> * @param id
>> * @param user
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void update(long id, User user);
>>
>> /**
>> *
>> * @param id
>> * @return REST: sends a 204 (NoContent) on success
>> * @exception REST: sends a 500 on any error
>> */
>> public void delete(long id);
>> }
>>
>
>
> -------------------------------------------------------------------------------- 
>
>
>
>> /*
>> * Copyright: (C) Innovation Investments
>> * Version:   $Revision: 1.4 $
>> * Modified:  $Date: 2009/05/14 12:02:05 $
>> * By: $Author: toeukps $
>> */
>> package nl.knowledgeplaza.profiler.services;
>>
>> import nl.knowledgeplaza.profiler.engine.model.User;
>> import nl.knowledgeplaza.profiler.services.support.Users;
>>
>> /**
>> *
>> * @author toeu
>> *
>> */
>> @javax.jws.WebService(endpointInterface = 
>> "nl.knowledgeplaza.profiler.services.UserService", serviceName = 
>> "users") // the "ws" prefix is handled by the container
>> @javax.ws.rs.Path("/users") // the "rest" prefix is handled by the 
>> container
>> @javax.ws.rs.Produces("application/xml")
>> public class UserServiceImpl extends AbstractServiceImpl<User, Users>
>> implements UserService
>> {
>> // 
>> =======================================================================
>> // CONSTRUCTOR
>>
>> /**
>> *
>> */
>> public UserServiceImpl()
>> {
>> super(User.class, Users.class);
>> }
>>
>> // 
>> =======================================================================
>> // SERVICES
>>
>> // TODO: we get an exception if this code is placed in the abstract 
>> class, CXF is looking into it
>> @javax.ws.rs.POST
>> @Override public void add(User user)
>> {
>> super.add(user);
>> }
>>
>> // TODO: we get an exception if this code is placed in the abstract 
>> class, CXF is looking into it
>> @javax.ws.rs.PUT
>> @javax.ws.rs.Path("/{id}")
>> @Override public void update(@javax.ws.rs.PathParam("id") long id, 
>> User user)
>> {
>> super.update(id, user);
>> }
>> }
>>
>
>


Mime
View raw message