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" <[email protected]>
To: <[email protected]>
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);
        }
}

Reply via email to