Scenario:
User "owns" contacts via an unidirectional @ManyToOne JPA mapping on
Contact.  Contact subclasses from a @MappedSuperclass  called
UserResource.

What I would like to do:

an Interface called ISubResourceService<T extends UserResource> that
has a CXF annotation of:
public interface ISubResourceService<T extends UserResource> {
        @GET
        @Produces("application/json")
        List<T> getAll(@PathParam("userId") Long userId)
                        throws DataNotFoundException;
}

and an Interface called IContactService extends
ISubResourceService<Contact> with contact specific annotations (such
as a class level @Path("/contact")) but no other (relevant to this
discussion) annotations or mappings.

finally, in the ideal world, the implementation:
public abstract class AbstractSubResourceService<T extends
UserResource> implements
                ISubResourceService<T> {
        @Override
        public List<T> getAll(Long userId) throws DataNotFoundException {
<code deleted for brevity>
        }
}

and of course: (ideally, no code other than the @Service for Spring to
pick it up need to go here)
@Service
public class ContactServiceImpl extends AbstractSubResourceService<Contact>
                implements IContactService {
}

The problem with the above implementation is that I get the "No
message body writer has been found for response class ArrayList"
error, which essentially is the problem when returning generic
collections, probably because of type erasure.

The following also return message body writer issues:
2) have AbstractSubResourceService return a Response, using entity(new
GenericEntity(List<T>){}), (we'll call this implementation 2, the base
is implementation 1)
3) have ContactService implement a getAll with the return signature
List<Contact> whose only code is "return super.getAll(userId);"
(implementation 3)
4) have IContactService do an @Override getAll with a return value of
List<Contact> (interface 2, same results vs all 3 implementations)
5) have IContactService copy getAll's declaration (with all CXF
annotations) with a return value of List<Contact> (interface 3, same
results vs all 3 implementations)
6) interface 3, remove the declaration of getAll in
ISubResourceService (call this interface 4), implementation (1 or 2)
AND 3 (see below for 2 without 3)

The following generates a no matching method WebApplicationException:
7) interface 4, implementation 1 or 2 (without 3)

The following works:
8) interface 4, implementation 3.

Based upon the above results:
1) GenericEntity is pointless if you are returning a generic
collection. (implementation 2 never worked, in any form)
2) having a sub interface "override" a super interface does not work
on an annotation basis (interface 2 and 3 does not work) possibly due
to retention when compiling?
3) I'm not quite sure why #7 returned no matching method.  Is there an
annotation retention issue that causes CXF not to "see" that the
getAll in AbstractSubResourceService has applicable annotations in
IContactService? (never mind that it's truly horrendous coding style.)

So anyways, I've got code that works, but isn't particularly ideal.
If anyone can shed light on how they've done similar work, or
suggestions, I'd be happy to try them out. Sergey, could you shed some
light on results 2 and 3?

thanks
Jeff

Reply via email to