Timo.
I hope you didn't waste much time on my last "cry out" for help.
Today, discussing it with a colleague, I compared the types returned on each step when doing it directly with the "Q" classes created by QueryDsl.
Something like this:
filtros = filtros.and(qSucursal.telefonos.any().telefono.eq("tel1"));
I discovered the any() element returns a "QTelefono", and that happens to be a
EntityPathBase<?> instead of a PathBuilder<?> as I had it declared.
Following the comparison of types and structure, I got to the solution.
I think I was banging my head to the same wall every time and ever took a step back and tried to see the big picture, I guess.
Thank you very much for all your help.
Following is the working code. Hope it helps someone else and that the Spanish words don't make it harder to understand.
I know I'm not an expert Java programmer, so any comments are very wellcome.
Ely.
public BooleanExpression processComparisonNode(String pNombreNodo, ComparisonNode pNode,
Map<String,Object> pParams, boolean multiValues) {
BooleanExpression result = null;
String atributoAFiltrar = pNode.getSelector();
Class<?> entidadClass = (Class<?>) pParams.get("EntityClass");
EntityPathBase<?> path = (EntityPathBase<?>) pParams.get("EntityPathBase"); // QueryDsl's "Q" generated class
@SuppressWarnings("unused")
Operator<java.lang.Boolean> ops;
if (! RsqlParserOperators.operators().contains(pNode.getOperator())) {
throw new EAppDataValidationException(ErrorCodesEnumDataValidation.DV_INVALID_DATA, "El operador recibido ["+pNode.getOperator()+"] no está definido.");
}
@SuppressWarnings("unchecked")
Map<String, RsqlParserConversionTiposBase> conversionTipos = (Map<String, RsqlParserConversionTiposBase>) pParams.get("ConversionTipos");
List<Comparable<?>> listaArgumentos = new ArrayList<Comparable<?>>(pNode.getArguments()); // RSQL Parser Node argument's to filter with
String dereferenceString = "";
String atributoAFiltrarOrig = atributoAFiltrar;
boolean isACollection = false;
Class<?> fieldArgClass = null;
ComparablePath<Comparable<?>> property = null;
EntityPathBase<?> collectionEntityPath = null;
try {
int cnt = 0;
boolean salir = (! atributoAFiltrar.contains("."));
do { // to check received attribute once without splitting at "." character and once already splitted (only when it was not found in the previous loop iteration)
cnt++;
logger.debug("(cnt es: "+cnt+", salir es: "+(salir ? "true" : "false")+") dereferenceString: " + dereferenceString);
logger.debug("(cnt es: "+cnt+", salir es: "+(salir ? "true" : "false")+") atributoAFiltrar: " + atributoAFiltrar);
for (Map.Entry<String, RsqlParserConversionTiposBase> entry : conversionTipos.entrySet())
{
//System.out.println(entry.getKey() + "/" + entry.getValue());
if ((entry != null)
&& (entry.getValue() != null)
&& (entry.getValue().getArgAdicional() != null)
&& (entry.getValue().getArgAdicional().equals(atributoAFiltrar))
&& (! entry.getKey().equals(atributoAFiltrar))) {
logger.debug("Se reemplaza el atributo recibido ["+atributoAFiltrar+"] por el real ["+entry.getKey()+"]");
atributoAFiltrar = entry.getKey();
salir = true;
break;
}
}
if (conversionTipos.containsKey(atributoAFiltrar)) {
salir = true;
RsqlParserConversionTiposBase convertidor = conversionTipos.get(atributoAFiltrar);
for (ListIterator<Comparable<?>> iterator = listaArgumentos.listIterator(); iterator.hasNext();) {
Comparable<?> elemento = iterator.next();
String argStrTmp = (String) elemento;
convertidor.setArg(argStrTmp);
try {
Comparable<?> comparableTmp = (Comparable<?>) convertidor.call();
iterator.set(comparableTmp);
} catch (Exception e) {
throw new EAppDataValidationException(ErrorCodesEnumDataValidation.DV_INVALID_DATA, e.getMessage(), e);
}
}
} else if (atributoAFiltrar.contains(".")) {
dereferenceString = StringUtils.substringBefore(atributoAFiltrar,".");
atributoAFiltrar = StringUtils.substringAfter(atributoAFiltrar,".");
logger.debug("origTmp = " + atributoAFiltrarOrig);
logger.debug("dereferenceString = " + dereferenceString);
logger.debug("atributoAFiltrar = " + atributoAFiltrar);
if (dereferenceString.length() > 0) {
try {
Field f = entidadClass.getDeclaredField(dereferenceString);
if (f.getType().isAssignableFrom(Collection.class)) {
isACollection = true;
logger.debug("ES UN ATRIBUTO DE TIPO COLECCIÓN");
Type genericFieldType = f.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
if ((fieldArgTypes == null) || (fieldArgTypes.length < 1)) {
String msg = "Solicitado filtrar por ["+atributoAFiltrarOrig+"]. No fue posible determinar el tipo de objetos contenidos en la colección.";
logger.error(msg);
throw new EAppInternalException(ErrorCodesEnumInternal.I_GENERIC_ERR, msg);
}
if (fieldArgTypes.length > 1) {
String msg = "Solicitado filtrar por ["+atributoAFiltrarOrig+"]. No está permitido filtrar dentro de un atributo de tipo colección con más de un tipo de objeto.";
logger.error(msg);
throw new EAppInternalException(ErrorCodesEnumInternal.I_NOT_PERMITED, msg);
}
fieldArgClass = (Class<?>) fieldArgTypes[0];
PathBuilder<?> entity = new PathBuilder<>(entidadClass, entidadClass.getSimpleName().toLowerCase());
collectionEntityPath = entity.getCollection(dereferenceString, fieldArgClass).any();
}
} else {
logger.debug("No es un atributo de tipo colección");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
///////////////////////////////////////////////////////////////////////
}
} while (cnt < 2 && !salir);
} finally {
if (dereferenceString.length() > 0) {
atributoAFiltrar = dereferenceString + "." + atributoAFiltrar;
}
}
if (listaArgumentos.size() > 0) {
if (isACollection) {
if (fieldArgClass == null) {
String msg = "Solicitado filtrar por ["+atributoAFiltrarOrig+"]. No fue posible determinar el tipo de objetos contenidos en la colección.";
logger.error(msg);
throw new EAppInternalException(ErrorCodesEnumInternal.I_GENERIC_ERR, msg);
}
property = new ComparablePath(fieldArgClass, collectionEntityPath, atributoAFiltrar);
} else {
property = new ComparablePath(entidadClass, path, atributoAFiltrar);
}
Comparable<?> primerArgumento = listaArgumentos.get(0);
if (RsqlParserOperators.EQUAL.equals(pNode.getOperator())) {
ops = Ops.EQ;
if (primerArgumento == null) {
result = property.isNull();
} else {
result = property.eq(primerArgumento);
}
} else if (RsqlParserOperators.IN.equals(pNode.getOperator())) {
ops = Ops.IN;
result =
property.in(listaArgumentos);
} else if (RsqlParserOperators.GREATER_THAN_OR_EQUAL.equals(pNode.getOperator())) {
ops = Ops.GOE;
validaNotNull(atributoAFiltrarOrig, primerArgumento, pNode.getOperator());
result = property.goe(primerArgumento);
} else if (RsqlParserOperators.GREATER_THAN.equals(pNode.getOperator())) {
ops = Ops.GT;
validaNotNull(atributoAFiltrarOrig, primerArgumento, pNode.getOperator());
result =
property.gt(primerArgumento);
} else if (RsqlParserOperators.LESS_THAN_OR_EQUAL.equals(pNode.getOperator())) {
ops = Ops.LOE;
validaNotNull(atributoAFiltrarOrig, primerArgumento, pNode.getOperator());
result = property.loe(primerArgumento);
} else if (RsqlParserOperators.LESS_THAN.equals(pNode.getOperator())) {
ops = Ops.LT;
validaNotNull(atributoAFiltrarOrig, primerArgumento, pNode.getOperator());
result =
property.lt(primerArgumento);
} else if (RsqlParserOperators.NOT_EQUAL.equals(pNode.getOperator())) {
ops = Ops.NE;
if (primerArgumento == null) {
result = property.isNotNull();
} else {
result =
property.ne(primerArgumento);
}
} else if (RsqlParserOperators.NOT_IN.equals(pNode.getOperator())) {
ops = Ops.NOT_IN;
result = property.notIn(listaArgumentos);
}
} else {
validaNotNull(atributoAFiltrarOrig, null, pNode.getOperator());
}
return result;
}
private void validaNotNull(String pAtributoAFiltrarOriginal,
Comparable<?> pArg, ComparisonOperator pOp) {
if (pArg == null) {
throw new EAppDataValidationException(ErrorCodesEnumDataValidation.DV_INVALID_DATA,
"El argumento recibido para el atributo ["+pAtributoAFiltrarOriginal+"] dió null al ser interpretado y no está "
+ "implementado el manejo de null's para el operador ["+pOp+"]");