package sk.nociar.jpacloner.selectors;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.CollectionAttribute;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
/**
* Type-safe property selector based on metamodel classes needed for type-safe
* Criteria queries as defined by JPA 2.
* See <a href='http://hibernate.org/orm/tooling/'>Hibernate Metamodel Generator</a>
* for more details. <br/>
* <b>NOTE:</b> this is an experimental feature
*
* @author Miroslav Nociar
*
* @param <X>
* type of entity
*/
public class Selector<X> {
protected final String path;
protected final Set<String> paths;
Selector(String path, Set<String> paths) {
this.path = path;
this.paths = paths;
}
public static <X> Selector<X> get(Class<X> root) {
return new Selector<X>("", new HashSet<String>());
}
public final <Y> Selector<Y> join(SingularAttribute<? super X, Y> attribute) {
return new Selector<Y>(createPath(attribute), paths);
}
public final <Y> Selector<Y> join(CollectionAttribute<? super X, Y> attribute) {
return new Selector<Y>(createPath(attribute), paths);
}
public final <Y> Selector<Y> join(ListAttribute<? super X, Y> attribute) {
return new Selector<Y>(createPath(attribute), paths);
}
public final <Y> Selector<Y> join(SetAttribute<? super X, Y> attribute) {
return new Selector<Y>(createPath(attribute), paths);
}
public final <K, V> MapSelector<K, V> join(MapAttribute<? super X, K, V> attribute) {
return new MapSelector<K, V>(createPath(attribute), paths);
}
private String createPath(Attribute<? super X, ?> attribute) {
final String path = getPath();
final String name = attribute.getName();
final String next = path.isEmpty() ? name : path + "." + name;
paths.add(next);
paths.remove(path);
paths.remove(this.path);
return next;
}
protected String getPath() {
return path;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
String delimiter = "";
for (String p : paths) {
sb.append(delimiter).append(p);
delimiter = "|";
}
return sb.toString();
}
}