Question

I have a Java class which has some field annotated with @SearchCriteria(criteria = "class1.class2.field"). criteria parameter inside annotation means for with class this field should be set as hibernate criteria, it mean that, if field marked for example:

@SearchCriteria(criteria = "class1.class2.field")
private String value;

I want dynamicly create hibernate criteria with looks like

DetachedCriteria hibernateCriteria = forClass(Class.class);
hibernateCriteria.createCriteria("class1").createCriteria("class2").add(eq("field", value));

Problem is than I can not set another criteria to already added, it mean I should check annotation criteria option.

      switch (annotationCriteria.length - 1) {
case 0:             
hibernateCriteria.add(isNull(annotationCriteria[0]));               
case 1:
hibernateCriteria.createCriteria(annotationCriteria[0]).add(                Restrictions.isNull(annotationCriteria[annotationCriteria.length - 1]));
case 2:   hibernateCriteria.createCriteria(annotationCriteria[0]).createCriteria(annotationCriteria[1]).add(                Restrictions.isNull(annotationCriteria[annotationCriteria.length - 1]));
    }

I want to remove this "swith". It is possible to get already added criteria by, I dont now, for example by "name" and that add new subcriteria for it.

Was it helpful?

Solution 2

I find out more "nice" solution for this issue. First of all create some searchCriteria class, for example:

public class SearchCriteria {

    @SearchCriteria(path = "someclass.someclass.id")
    private Integer someId;

    public Integer getSomeId() {
        return someId;
    }

    public void setSomeId(Integer someId) {
        this.someId= someId;
    }
}

And custom annotation:

@Target(value = { ElementType.FIELD })
@Retention(RUNTIME)
public @interface SearchCriteria {
    String path() default "";

    boolean optional() default true;
}

And in DAO class:

@Override
    public Collection<SomeClass> find(SearchCriteria criteria) {
        DetachedCriteria hibernateCriteria = forClass(SomeClass.class);

        for (Field field : criteria.getClass().getDeclaredFields()) {
            Annotation annotation = field.getAnnotation(SearchCriteria.class);

            if (annotation == null) {
                continue;
            }

            List<String> elements = Arrays.asList(StringUtils.split(((SearchCriteria) annotation).path(), "."));

            field.setAccessible(true);
            Object fieldValue = null;
            try {
                fieldValue = field.get(criteria);
            } catch (IllegalArgumentException e) {
                LOG.error("while trying to get private field value of entity " + SearchCriteria.class, e);
            } catch (IllegalAccessException e) {
                LOG.error("while trying to get private field value of entity " + SearchCriteria.class, e);
            }

            for (String element : elements) {
                if (elements.indexOf(element) == elements.size() - 1) {
                    hibernateCriteria = hibernateCriteria.add(eq(element, fieldValue));
                } else {
                    hibernateCriteria = hibernateCriteria.createCriteria(element);
                }
            }
        }

        return getHibernateTemplate().findByCriteria(hibernateCriteria);
    }

OTHER TIPS

No, it's not possible. Detached Criteria API does not - for better or worse - allow for discovery, so you won't be able to ask it for "existing" criteria.

What you can do, however, is maintain your own map of nested criteria by association path. In pseudo-code:

Map<String, DetachedCriteria> criteriaMap = ...;

for ( ) { // loop over annotation criteria's "elements"
    DetachedCriteria existing = criteriaMap.get(fullPath);
    if (existing==null) {
        existing = parentCriteria.createCriteria(pathElement);
        criteriaMap.put(fullPath, existing);
    }
    existing.add(whateverCondition);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top