This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 189723 - Simplify "REST from Entity" wizard in Java EE 5
Summary: Simplify "REST from Entity" wizard in Java EE 5
Status: RESOLVED FIXED
Alias: None
Product: webservices
Classification: Unclassified
Component: REST (show other bugs)
Version: 7.0
Hardware: All All
: P2 normal (vote)
Assignee: Denis Anisimov
URL:
Keywords: PLAN
Depends on: 192981
Blocks:
  Show dependency tree
 
Reported: 2010-08-20 16:53 UTC by Milan Kuchtiak
Modified: 2011-07-21 14:33 UTC (History)
4 users (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments
stacktrace (4.44 KB, text/plain)
2010-12-06 16:47 UTC, Denis Anisimov
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Milan Kuchtiak 2010-08-20 16:53:33 UTC
Currently, in Java EE 5 project type, a complicated set of classes is generated for each entity class.

E.g. for Customer class there are :
CustomersResource
CustomerResource
CustomersConverter
CustomerConverter
UriResolver                 // one for all resources
PersistenceService          // one for all resources


We can re-use the JPA controller wizard and generate a RESTFacade class that will delegate to JpaController:

CustomerRESTFacade          // will delegate to CustomerJpaController
CustomerJpaController
IllegalOrphanException      // one for all resources
NonexistingEntityException  // one for all resources
PreexistingEntityException  // one for all resources
RollbackFailureException    // one for all resources

Thus, basically, we can reduce the number of generated classes, and also be compatible with other Netbeans feature (JPA controller)

This is the sample code that can be generated :

@Path("/customer")
public class CustomerRESTFacade {
    private CustomerJpaController jpaController;
    
    public CustomerRESTFacade() {
        jpaController = getJpaController();
    }
    
    /** get all Customers */
    @GET
    @Produces({"application/xml", "application/json"})
    public List<Customer> findCustomerEntities() {
        return jpaControler.findCustomerEntities();
    }

    /** create new Customer */
    @PUT
    @Consumes({"application/xml", "application/json"})
    public Response create(Customer entity) {
        try {
            jpaControler.create(entity);
            return Response.created("..").build();
        } catch (Exception ex) {
            return Response.notModified(ex.getMessage()).build();
        }
    }
    
    /** get Customers count */
    @GET
    @Path("count")
    @Produces("text/plain")
    public String getCount() {
        return String.valueOf(jpaControler.getCustomerCount());
    }

    // similarly delegate to other JpaController methods, like
    // edit
    // destroy
    // findCustomer
    
    private CustomerJpaController getJpaController() {
        try {
            EntityManagerFactory emf = (EntityManagerFactory) new InitialContext().lookup("java:comp/env/persistence-factory");
            UserTransaction utx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
            return new CustomerJpaController(utx, emf);
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Also that would be necessary to insert 2 entries to web.xml :
    <resource-ref>
        <res-ref-name>UserTransaction</res-ref-name>
        <res-type>javax.transaction.UserTransaction</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
    <persistence-unit-ref>
        <persistence-unit-ref-name>persistence-factory</persistence-unit-ref-name>
        <persistence-unit-name>WebApplicationPU</persistence-unit-name>
    </persistence-unit-ref>

Please, review the suggested code.
I've already tested that.
Comment 1 David Konecny 2010-08-23 01:50:01 UTC
> @Path("/customer")
> public class CustomerRESTFacade {

According to "Table EE.5-1 Component classes supporting injection" in EE6 spec (page 67) 'JAX-RS root resource classes' support injection so you should not need JNDI lookup in CustomerRESTFacade but injection should do the trick.
Comment 2 Petr Jiricka 2010-08-23 07:27:38 UTC
> According to "Table EE.5-1 Component classes supporting injection" in EE6 spec

Yes, but this is EE 5. Does it also apply? I think in the EE 6 case injection is used already - see also bug 181161, from which this one was spun off (possibly bug 173984 is also related).
Comment 3 Milan Kuchtiak 2010-08-23 08:02:21 UTC
Yes, this is about Java EE 5, where the injections are not fully supported in REST resources.

For Java EE 6 (REST from Entity), I've reported another enhancement:
- issue 189761
Comment 4 David Konecny 2010-08-23 21:14:31 UTC
(In reply to comment #3)
> Yes, this is about Java EE 5, where the injections are not fully supported in
> REST resources.
> 
> For Java EE 6 (REST from Entity), I've reported another enhancement:
> - issue 189761

Right, in EE5 injection is required only for JAX-WS but not for JAX-RS.
Comment 5 David Konecny 2010-08-26 02:15:51 UTC
Milan, I tried to find somewhere specified what exactly must be done for EE5 and I was not successful but:

* several sources say that UserTransction is always available under JNDI name java:comp/UserTransaction and therefore web.xml entry should not be needed. I tested it on GFv2 and it does work without web.xml record

* to access EntityManagerFactory for your PU you need to map JNDI entry to your PU but instead of web.xml record you could just add @PersistenceContext(unitName="WebApplicationPU", name="persistence-factory") to class level of you POJO. Again, I tested it on GFv2 and it works.

I would prefer to avoid web.xml if possible as it is extra configuration source. Can you double check please? Thx.
Comment 6 Milan Kuchtiak 2010-08-26 08:30:32 UTC
Thanks,

Tested with GlassFish V31

< * several sources say that UserTransction is always available under JNDI name
java:comp/UserTransaction and therefore web.xml entry should not be needed. I
tested it on GFv2 and it does work without web.xml record

- works fine

< * to access EntityManagerFactory for your PU you need to map JNDI entry to your
PU but instead of web.xml record you could just add
@PersistenceContext(unitName="WebApplicationPU", name="persistence-factory") to
class level of you POJO. Again, I tested it on GFv2 and it works.

- I got:
java.lang.ClassCastException: com.sun.enterprise.container.common.impl.EntityManagerWrapper cannot be cast to javax.persistence.EntityManagerFactory

Can you David evaluate if this is a GlassFish bug or not.
I wonder if there is any specification how to create an instance of EntityManagerFactory properly.
Comment 7 Milan Kuchtiak 2010-08-26 08:42:47 UTC
In GlassFish V3, the injection for EntityManagerFactory object simply fails: object isn't initialized(null)
David - have you tested that on some REST resource inside the web container?
Comment 8 Milan Kuchtiak 2010-08-26 09:29:33 UTC
< * several sources say that UserTransction is always available under JNDI name
java:comp/UserTransaction and therefore web.xml entry should not be needed. I
tested it on GFv2 and it does work without web.xml record

It's likely because the UserTransaction JNDI resource is, likely by default, available in GlassFish, unlike in Tomcat server:

see:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html
Comment 9 David Konecny 2010-08-26 21:45:49 UTC
Sorry for confusing you Milan. If you need to lookup EntityManagerFactory then you must use @PersistenceUnit annotation on your class. When you use @PersistenceContext annotation then EntityManager will be looked up.

(In reply to comment #8)
> It's likely because the UserTransaction JNDI resource is, likely by default,
> available in GlassFish, unlike in Tomcat server:

The problem with Tomcat is that it is not EE server - it is just web container and so likely persistence annotations may or may not work as Tomcat does not come with persistence support. I would be tempted to implement this properly for EE servers and later either handle Tomcat specially (by generating web.xml records) or ... do nothing? Let user's fix this for Tomat? Wait for EE Web Profile Tomcat? I'm not sure. What do you think?
Comment 10 David Konecny 2010-09-01 22:28:59 UTC
(In reply to comment #5)
> * to access EntityManagerFactory for your PU you need to map JNDI entry to your
> PU but instead of web.xml record you could just add
> @PersistenceContext(unitName="WebApplicationPU", name="persistence-factory") to
> class level of you POJO.

Put this on hold for now: JPA spec talks about @PersistenceContext only in context of EJBs or managed objects. Applying it on POJOs might not be complaint with the spec despite it being supported by GlassFish implementation and so we should not recommend it. I'm trying to clarify this.
Comment 11 Denis Anisimov 2010-12-06 16:46:51 UTC
I'm trying to follow suggested code pattern and have realized the problem 
with JPA Controller.
For some reason it doesn't work.
I need a help with generated controller.

So the problem has no any relation to THIS RFE.
Here are the steps which I have used :
- Create a WEB JEE5 project with target server GF2.
- Create entities for table(s) ( I have used sample Derby database and 
tables: customer and discount code ).
- Create JPA controller classes from entities .
- This step is just interface to call JPA controller methods:
create RESTful web service and method of WS which delegates "create()" method
call of JPA controller.

Additional info :
- See the code from original description of this issue for access to JPA 
controller
- I'm using TopLink Essentials persistence provider.

Call of WS method ( f.e. using the test RESTful WS action of NB ) lead to 
exception in the JPA Controller. See attached exception.
Please note that it happens on call of start transaction method of entity 
manager:
em.getTransaction().begin();

We need to resolve this issue before I will decide to change generated code.
Comment 12 Denis Anisimov 2010-12-06 16:47:27 UTC
Created attachment 103629 [details]
stacktrace
Comment 13 Sergey Petrov 2010-12-07 12:24:18 UTC
looks like an issue for me, code for jpa controller is different from one generated in case of jsf from entities.
Comment 14 Denis Anisimov 2010-12-07 12:32:40 UTC
OK, thanks, I will file a bug.
Comment 15 Denis Anisimov 2010-12-07 14:02:49 UTC
I have filed a bug #192981 about inconvenient behavior of generated 
JPA Controller .
We can use different classes generation approach: do not rely on 
existed functionality of JPA controller. The required code from JPA controller
could be put into generated RESTFacade classes directly.
But it seems it is not a good solution.
Generated code could be potentially duplicate by developer in case of
some non trivial entities usage in Web application.

Also the current generation strategy has some preference against final 
result of "improvement" version. Although the code becomes plainer but
result of methods which return collection is less obvious.
XxxxsConverter is used as aggregate class for collection of entities.
It allows to generate XML response when collection entities should be 
returned.
Otherwise ( List<Xxxx> is return type of method ) json MIME type is used
and response is not XML content.
User should adopt generated code for getting XML content instead of json.
The simplest way to adopt the code is creation of XXXxxsConverter.

As result I postpone the decision for this issue to future.
It seems it is not so obvious that suggested approach is better than existed 
one. And it is also blocked by #192981
Comment 16 Sergey Petrov 2010-12-07 14:05:31 UTC
current behavior generate proper jpa controller in case of jsf from entities, 192981 is issue for stand alone jpa controller generation, is it really blocker for this enhancement?
Comment 17 Denis Anisimov 2010-12-07 14:28:25 UTC
Hm, I need to investigate the possibility of JPA controller generation code 
reusage ( from JSF Pages from Entities ).
It seems that generated code ( JPA controllers ) is good enough for 
the current issue.
Probably the JPA controller code generation strategy could be really used
and #192981 doesn't block this bug.
Comment 18 Denis Anisimov 2010-12-08 12:57:05 UTC
OK , I have investigated the "JSF Pages from Entity Classes..." wizard code.
The short conclusion : it cannot be used for resolving current RFE and I need 
to have bug #192981 fixed. So issue #192981 is still stopper.

Detailed explanation :
Generation code for "JSF Pages..." actions is located inside web.jsf module which
is not good as dependency for websvc.rest definitely even without detailed code
investigation. 
"JSF Pages..." wizard is written in the way which doesn't allow direct reusage.
It's purpose is not "JPA controller" generation but all source code required 
for JSF generation. So it is strictly JSF centered. 
It is not so easy to distinguish and reuse just "JPA controller" generation 
logic from the whole generation logic.
On the other hand "JPA Controller Classes from Entity Classes" wizard has a very
good design which can be reused with minimal changes.

From my point of view : "JSF Pages..." generation logic SHOULD reuse itself 
"JPA Controller Classes from Entity Classes" generation logic to avoid
code duplication.

So I really need to have #192981 fixed.
Comment 19 David Konecny 2010-12-08 21:04:51 UTC
(In reply to comment #18)
> From my point of view : "JSF Pages..." generation logic SHOULD reuse itself 
> "JPA Controller Classes from Entity Classes" generation logic to avoid
> code duplication.

Denis, could you file an issue please for it to happen? Thanks.
Comment 20 Denis Anisimov 2010-12-09 08:54:19 UTC
Sorry I was wrong.
There is no code duplication.  I have missed the call of JpaControllerIterator.generateJpaControllers() method inside "JSF Pages..." 
wizard iterator. The latter code has a similar method names for JSF controllers
which I mixed up.
So the code is perfectly reused.
Comment 21 Denis Anisimov 2010-12-14 09:01:51 UTC
The fix for this RFE requires a huge number of code modification.
It will have a strong impact on important RESTful from entities/DB functionality.
Common generation code strategy needs to be rewritten along with various cases:
1) additional generation logic for JEE5
2) additional generation logic for Spring

The current approach will dramatically change. So it is very risky to do this
for upcoming 7.0 release.
I'm working on this RFE but result will be committed to the trunk only 
for next version .
Comment 22 Petr Jiricka 2010-12-14 13:18:32 UTC
If the changes are large, then I agree it should be deferred to the next release.
Comment 23 Denis Anisimov 2010-12-14 13:31:13 UTC
The code changes dramatically . It concerns the functionality under subject
and related functionality.

I think the rewriting of the existing code will be ready on the next week.
But as I understand WS functionality is not tested seriously.
As result of this RFE fix one needs to perform deep testing for
1) RESTful from Enities
2) RESTful from DB

Each item for : JEE6, JEE5 , String support.

There are a lot of testing. 
So I really afraid that the fix could break existing functionality.
Comment 24 Denis Anisimov 2011-05-13 15:08:14 UTC
web-main
changeset:   193977:d15e95287f01
Comment 25 Petr Jiricka 2011-05-26 14:44:00 UTC
Not in 7.0.1 -> TM=Dev.
Comment 26 Quality Engineering 2011-07-21 14:33:47 UTC
Integrated into 'main-golden'
Changeset: http://hg.netbeans.org/main-golden/rev/2eb7d9687b23
User: Vladimir Riha <vriha@netbeans.org>
Log: QA - updated REST tests to be consistent with #189723 and some other minor updates