We want to refactor two methods that are exactly the same, except for one difference: one takes an org.hibernate.Criteria
and the other org.hibernate.criterion.DetachedCriteria
. These two do implement a mutual interface (org.hibernate.criterion.CriteriaSpecification
), but this only contains some final static fields, and no methods.
Here are the methods (removed comments and javadoc for compactness):
public static DetachedCriteria applyRestrictionsToCriteria(final DetachedCriteria criteria,
final Vector<RestrictionsHelper> filter) {
final Map<String, DetachedCriteria> subCriteriaMap = new HashMap<>();
if (filter != null) {
final Iterator<RestrictionsHelper> itp = filter.iterator();
while (itp.hasNext()) {
final RestrictionsHelper restric = itp.next();
if (restric.getClassname().equals("")) {
final Iterator<Criterion> ir = restric.getCriterions().iterator();
while (ir.hasNext()) {
final Criterion criterion = ir.next();
criteria.add(criterion);
if (criterion.toString().contains("Happening_fk")) {
criteria.setFetchMode("Happeningdetails", FetchMode.JOIN);
}
}
final Iterator<Order> or = restric.getOrders().iterator();
while (or.hasNext()) {
criteria.addOrder(or.next());
}
} else {
final String[] buff = restric.getClassname().split("\\.");
DetachedCriteria subcriteria = criteria;
String path = "";
for (final String element : buff) {
final String[] name = getNameAndAlias(element);
path += name[0];
final DetachedCriteria exsubcriteria = subCriteriaMap.get(path);
if (exsubcriteria == null) {
subcriteria = subcriteria.createCriteria(name[0], name[1], CriteriaSpecification.LEFT_JOIN);
subCriteriaMap.put(path, subcriteria);
} else {
subcriteria = exsubcriteria;
}
path += ".";
}
final Iterator<Criterion> ir = restric.getCriterions().iterator();
while (ir.hasNext()) {
subcriteria.add(ir.next());
}
final Iterator<Order> or = restric.getOrders().iterator();
while (or.hasNext()) {
subcriteria.addOrder(or.next());
}
}
}
}
return criteria;
}
and
public static Criteria applyRestrictionsToCriteria(final Vector<RestrictionsHelper> filter,
final Criteria criteria) {
final Map<String, Criteria> subCriteriaMap = new HashMap<String, Criteria>();
if (filter != null) {
final Iterator<RestrictionsHelper> itp = filter.iterator();
while (itp.hasNext()) {
final RestrictionsHelper restric = itp.next();
if (restric.getClassname().equals("")) {
final Iterator<Criterion> ir = restric.getCriterions().iterator();
while (ir.hasNext()) {
final Criterion criterion = ir.next();
criteria.add(criterion);
if (criterion.toString().contains("Happening_fk")) {
criteria.setFetchMode("Happeningdetails", FetchMode.JOIN);
}
}
final Iterator<Order> or = restric.getOrders().iterator();
while (or.hasNext()) {
criteria.addOrder(or.next());
}
} else {
final String[] buff = restric.getClassname().split("\\.");
Criteria subcriteria = criteria;
String path = "";
for (final String element : buff) {
final String[] name = getNameAndAlias(element);
path += name[0];
final Criteria exsubcriteria = subCriteriaMap.get(path);
if (exsubcriteria == null) {
subcriteria = subcriteria.createCriteria(name[0], name[1], CriteriaSpecification.LEFT_JOIN);
subCriteriaMap.put(path, subcriteria);
} else {
subcriteria = exsubcriteria;
}
path += ".";
}
final Iterator<Criterion> ir = restric.getCriterions().iterator();
while (ir.hasNext()) {
subcriteria.add(ir.next());
}
final Iterator<Order> or = restric.getOrders().iterator();
while (or.hasNext()) {
subcriteria.addOrder(or.next());
}
}
}
}
return criteria;
}
Since both methods do the same, we obviously want to refactor it into one method.
Some things we've tried without result
Creating an interface (
GenericCriteria
) and two subclasses:public class OwnCriteria extends CriteriaImpl implements GenericCriteria
and
public class OwnDetachedCriteria extends DetachedCriteria implements GenericCriteria
and use that interface in the method.
Problem:
- We use
Criteria#createCriteria(String, String, int)
which returns anew Subcriteria(this, String, String, int);
. BecauseSubcriteria
is a final class, we can't create our own sub-class and we also can't make a convert-constructor in our Own classes because there aren't getters for all required constructor-parameters.
- We use
Directly make an anonymous class from the interface (i.e.
new BagGenericCriteria(){ @Override ... }
Possible work-around that will most likely work, but is rather ugly:
Using the shared interface (org.hibernate.criterion.CriteriaSpecification
) as parameter and then use multiple instanceof
checks for one or the other.
Notes
- We use Java 7 (so we can't use Java 8 features - for now)
- We use hibernate version 3.3.2.GA (so we can't use hibernate 4+ - for now)
- Some other parts of the code in the methods can be refactored as well, but right now we just want to have two exact identical methods (apart from the parameter used) refactored into one.