You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Jim Talbut <jt...@spudsoft.co.uk> on 2013/10/21 08:21:13 UTC

Correct way to use a JPA*QueryVisitor with a filter class that is not a JPA entity

Hi,

I have a JPA data model that I'm trying to use with CXF's SearchContext.

In order to constrain the searching that can be done I'm trying to use a 
search class that is not a JPA entity (and that just contains a subset 
of the JPA fields).
Q1. Is this the right way to solve this problem?
Q2. How should I get it to work?

Details:

I have a "User" interface that the "User_JpaImpl" entity class derives from.
I also have a "UserFilter" class that just has two properties (username 
& enabled) - the User interface also has getters and setters for these 
properties, but there is no relationship between UserFilter and User (or 
User_JpaImpl).

My best attempt so far looks like this:
         SearchCondition<UserFilter> sc = 
searchContext.getCondition(UserFilter.class);
         JPACriteriaQueryVisitor<UserFilter, User_JpaImpl> visitor =
             new JPACriteriaQueryVisitor<>(entityManager, 
UserFilter.class, User_JpaImpl.class);
         searchCondition.accept(visitor);

         TypedQuery<User_JpaImpl> query = visitor.getTypedQuery();
         List<? extends User> result = query.getResultList();

This throws an exception in accept because of this:
         if (builder == null) {
             builder = em.getCriteriaBuilder();
             cq = builder.createQuery(queryClass);
             root = cq.from(tClass);
             predStack.push(new ArrayList<Predicate>());
         }

tClass is UserFilter.class, which is not known to JPA and thus cannot be 
used as root (cq.from(tClass) throws IllegalArgumentException).


All I want to do is limit the set of fields that can be queried, if this 
is the wrong approach I'm happy to swap it for another.

Thanks.

Jim

Re: Correct way to use a JPA*QueryVisitor with a filter class that is not a JPA entity

Posted by Sergey Beryozkin <sb...@gmail.com>.
The exception is now propagated by default, in CXF 2.7.8 it will be 
possible to get it propagated by setting a 
"search.block.search.extension" to false

Sergey
On 21/10/13 21:07, Jim Talbut wrote:
> On 21/10/2013 10:18, Sergey Beryozkin wrote:
>> I believe the JPA2 way is to use either JPA2 Tuple or capturing
>> beans/arrays which will filter  the 'username' & 'enabled' properties
>> at JPA/DB level, the JPA2 section has a couple of examples and
>> JPATypedQueryVisitorTest has few more (to do with different styles of
>> shaping the output), I'd probably go for using Tuple.
>>
>> If you prefer to use a custom UserFilter then I guess you'd need to use
>> JPATypedQueryVisitor<User_JpaImpl> and then filter the result list
>> with the filter afterwards
>
> Thanks, I think I'm going to go with using another visitor just to do my
> validation, and then use the simple TypedQuery - any other approach
> seems to create more complexity (for my scenario) than it's worth.
>
> Is there a reason why any errors in the parsing are silently swallowed
> in SearchContextImpl.getCondition():
>          if (theExpression != null) {
>              try {
>                  return parser.parse(theExpression);
>              } catch (SearchParseException ex) {
>                  return null;
>              }
>          } else {
>              return null;
>          }
>
> Thanks again.
>
> Jim


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: Correct way to use a JPA*QueryVisitor with a filter class that is not a JPA entity

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 21/10/13 21:07, Jim Talbut wrote:
> On 21/10/2013 10:18, Sergey Beryozkin wrote:
>> I believe the JPA2 way is to use either JPA2 Tuple or capturing
>> beans/arrays which will filter  the 'username' & 'enabled' properties
>> at JPA/DB level, the JPA2 section has a couple of examples and
>> JPATypedQueryVisitorTest has few more (to do with different styles of
>> shaping the output), I'd probably go for using Tuple.
>>
>> If you prefer to use a custom UserFilter then I guess you'd need to use
>> JPATypedQueryVisitor<User_JpaImpl> and then filter the result list
>> with the filter afterwards
>
> Thanks, I think I'm going to go with using another visitor just to do my
> validation, and then use the simple TypedQuery - any other approach
> seems to create more complexity (for my scenario) than it's worth.

The metadata can be generated with the JPA impl plugin, the plus - the 
faster retrieval times I guess

>
> Is there a reason why any errors in the parsing are silently swallowed
> in SearchContextImpl.getCondition():
>          if (theExpression != null) {
>              try {
>                  return parser.parse(theExpression);
>              } catch (SearchParseException ex) {
>                  return null;
>              }
>          } else {
>              return null;
>          }
>
Right, originally I thought that typically, if one goes and query some 
web site and mistypes a query name then one would still get some default 
OK response, as opposed to some 400.

So if you get 'null' then assume that the default representation is to 
be returned, given that the query parameters are usually optional anyway.

However, I agree this approach may have its limitations, I think that 
for 3.0 only, we need to push the responsibility a bit higher to the 
application code, the good practice would still most likely be to 
proceed with returning a default rep, but may be the application code 
will decide to do something else

Cheers, Sergey

> Thanks again.
>
> Jim



Re: Correct way to use a JPA*QueryVisitor with a filter class that is not a JPA entity

Posted by Jim Talbut <jt...@spudsoft.co.uk>.
On 21/10/2013 10:18, Sergey Beryozkin wrote:
> I believe the JPA2 way is to use either JPA2 Tuple or capturing 
> beans/arrays which will filter  the 'username' & 'enabled' properties 
> at JPA/DB level, the JPA2 section has a couple of examples and 
> JPATypedQueryVisitorTest has few more (to do with different styles of 
> shaping the output), I'd probably go for using Tuple.
>
> If you prefer to use a custom UserFilter then I guess you'd need to use
> JPATypedQueryVisitor<User_JpaImpl> and then filter the result list 
> with the filter afterwards

Thanks, I think I'm going to go with using another visitor just to do my 
validation, and then use the simple TypedQuery - any other approach 
seems to create more complexity (for my scenario) than it's worth.

Is there a reason why any errors in the parsing are silently swallowed 
in SearchContextImpl.getCondition():
         if (theExpression != null) {
             try {
                 return parser.parse(theExpression);
             } catch (SearchParseException ex) {
                 return null;
             }
         } else {
             return null;
         }

Thanks again.

Jim

Re: Correct way to use a JPA*QueryVisitor with a filter class that is not a JPA entity

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi
On 21/10/13 07:21, Jim Talbut wrote:
> Hi,
>
> I have a JPA data model that I'm trying to use with CXF's SearchContext.
>
> In order to constrain the searching that can be done I'm trying to use a
> search class that is not a JPA entity (and that just contains a subset
> of the JPA fields).
> Q1. Is this the right way to solve this problem?
> Q2. How should I get it to work?
>
> Details:
>
> I have a "User" interface that the "User_JpaImpl" entity class derives
> from.
> I also have a "UserFilter" class that just has two properties (username
> & enabled) - the User interface also has getters and setters for these
> properties, but there is no relationship between UserFilter and User (or
> User_JpaImpl).
>
> My best attempt so far looks like this:
>          SearchCondition<UserFilter> sc =
> searchContext.getCondition(UserFilter.class);
>          JPACriteriaQueryVisitor<UserFilter, User_JpaImpl> visitor =
>              new JPACriteriaQueryVisitor<>(entityManager,
> UserFilter.class, User_JpaImpl.class);
>          searchCondition.accept(visitor);
>
>          TypedQuery<User_JpaImpl> query = visitor.getTypedQuery();
>          List<? extends User> result = query.getResultList();
>
> This throws an exception in accept because of this:
>          if (builder == null) {
>              builder = em.getCriteriaBuilder();
>              cq = builder.createQuery(queryClass);
>              root = cq.from(tClass);
>              predStack.push(new ArrayList<Predicate>());
>          }
>
> tClass is UserFilter.class, which is not known to JPA and thus cannot be
> used as root (cq.from(tClass) throws IllegalArgumentException).
>
>
> All I want to do is limit the set of fields that can be queried, if this
> is the wrong approach I'm happy to swap it for another.
>

I believe the JPA2 way is to use either JPA2 Tuple or capturing 
beans/arrays which will filter  the 'username' & 'enabled' properties at 
JPA/DB level, the JPA2 section has a couple of examples and 
JPATypedQueryVisitorTest has few more (to do with different styles of 
shaping the output), I'd probably go for using Tuple.

If you prefer to use a custom UserFilter then I guess you'd need to use
JPATypedQueryVisitor<User_JpaImpl> and then filter the result list with 
the filter afterwards

Thanks, Sergey

> Thanks.
>
> Jim