querydsl / querydsl

Unified Queries for Java
https://querydsl.com
Apache License 2.0
4.74k stars 873 forks source link

@QueryInit in child class fails if @QueryInit is not null in his parent. #336

Closed lhwaisman closed 11 years ago

lhwaisman commented 11 years ago

The problem exists in method "as" when the child class is initialized from a parent class.Example:

class Parent { private int x; @QueryInit("") private OtherClass z; } class Child extends Parent { @QueryInit("") private OtherClassTwo y; }

When child class is created "QChild c = QParent.parent.as(QChild.class)" his QueryInit fails because the method "as" inject (if INITS of Parent is not null) the INITS of Parent without check if INITS of child class is not null.

public <U extends BeanPath<? extends T>> U as(Class clazz) { try { if (!casts.containsKey(clazz)) { U rv; if (inits != null) { rv = clazz.getConstructor(PathMetadata.class, PathInits.class).newInstance(this.getMetadata(), inits); } else { rv = clazz.getConstructor(PathMetadata.class).newInstance(this.getMetadata()); } casts.put(clazz, rv); return rv; } else { return (U) casts.get(clazz); } .....

Sorry by my English. Thanks Version of QueryDsl : 2.7.3

timowest commented 11 years ago

It doesn't fail, if just takes the inits of the left hands side path, that's all.

What kind of change do you suggest?

You need to be aware that there are cases where the left hand side inits are broader than the right hand side, so always picking the left hand side inits is not an option.

How do you use the path.as(QType) functionality?

lhwaisman commented 11 years ago

My suggestion is that you can combine the properties of the parent class to the child class properties. This was the solution I had to implement to solve the problem described. The solution was:

private static final QOrden o = QOrden.orden;

public static BooleanExpression byZona(Zona zona) { // WARN: INITS harcodeado. Cuando se trata de que clase hija con @QueryInit no // funciona si su padre tiene @QueryInit (porque no se combinan). QOrden o2 = new QOrden(o.getMetadata(), new PathInits("cuota.zona", "cuota.socio", "total.*")); QRecibo r3 = o2.as(QRecibo.class); return r3.cuota.zona.eq(zona); }

Where is the child class Receipt of Order. Both classes have @ QueryInit defined in various properties, as shown in PathInits new ("cuota.zona" "cuota.socio", "total. *")); Being "cuota" Receipt own property and "total" Order (and inherited by Receipt)

@Entity public class Recibo extends Orden {

@QueryInit(value={"zona", "socio"})
@NotNull
@ManyToOne(cascade= CascadeType.MERGE)    
private Cuota cuota;

.... }

@Entity public class Orden { @Valid @QueryInit("*") private Dinero total;

 ....

}

Thanks

timowest commented 11 years ago

My suggestion is that you can combine the properties of the parent class to the child class properties.

I implemented now the following rules in the as method

  • if the original path is a root path then the new path will have the top level inits of the child which are guaranteed to include the parent inits
  • otherwise the parent inits are taken

PathMetadata.isRoot() returns now true for direct variable paths and paths that are delegates to variable paths.

timowest commented 11 years ago

Released in 3.0.0.BETA2