| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.persistence.criteria; |
| |
| import java.util.ArrayList; |
| |
| import javax.persistence.criteria.AbstractQuery; |
| import javax.persistence.criteria.CollectionJoin; |
| import javax.persistence.criteria.Expression; |
| import javax.persistence.criteria.Join; |
| import javax.persistence.criteria.JoinType; |
| import javax.persistence.criteria.ListJoin; |
| import javax.persistence.criteria.MapJoin; |
| import javax.persistence.criteria.Path; |
| import javax.persistence.criteria.PluralJoin; |
| import javax.persistence.criteria.Predicate; |
| import javax.persistence.criteria.SetJoin; |
| import javax.persistence.metamodel.Attribute; |
| import javax.persistence.metamodel.CollectionAttribute; |
| import javax.persistence.metamodel.ListAttribute; |
| import javax.persistence.metamodel.MapAttribute; |
| import javax.persistence.metamodel.PluralAttribute; |
| import javax.persistence.metamodel.SetAttribute; |
| import javax.persistence.metamodel.Type; |
| |
| import org.apache.openjpa.kernel.exps.AbstractExpressionBuilder; |
| import org.apache.openjpa.kernel.exps.ExpressionFactory; |
| import org.apache.openjpa.kernel.exps.Value; |
| import org.apache.openjpa.meta.ClassMetaData; |
| import org.apache.openjpa.meta.FieldMetaData; |
| import org.apache.openjpa.meta.JavaTypes; |
| import org.apache.openjpa.persistence.meta.AbstractManagedType; |
| import org.apache.openjpa.persistence.meta.Members; |
| import org.apache.openjpa.persistence.meta.Members.KeyAttributeImpl; |
| import org.apache.openjpa.persistence.meta.Members.MapAttributeImpl; |
| import org.apache.openjpa.persistence.meta.Members.Member; |
| |
| /** |
| * Implements strongly-typed Join expressions via singular and plural attributes. |
| * |
| * @author Fay Wang |
| * @author Pinaki Poddar |
| * |
| * @since 2.0.0 |
| * |
| */ |
| abstract class Joins { |
| |
| static Join clone(Join join) { |
| java.util.List<Members.Member> members = new ArrayList<>(); |
| java.util.List<JoinType> jts = new ArrayList<>(); |
| FromImpl<?, ?> root = getMembers((PathImpl)join, members, jts); |
| Members.Member<?, ?> member = members.get(0); |
| JoinType jt = jts.get(0); |
| Join join1 = makeJoin(root, member, jt); |
| for (int i = 1; i < members.size(); i++) |
| join1 = makeJoin((FromImpl<?, ?>) join1, members.get(i), jts.get(i)); |
| |
| return join1; |
| } |
| |
| static Join<?, ?> makeJoin(FromImpl<?, ?> from, Members.Member member, |
| JoinType jt) { |
| if (member instanceof Members.SingularAttributeImpl) |
| return new Joins.SingularJoin(from, |
| (Members.SingularAttributeImpl) member, jt); |
| else if (member instanceof Members.CollectionAttributeImpl) |
| return new Joins.Collection(from, |
| (Members.CollectionAttributeImpl) member, jt); |
| else if (member instanceof Members.ListAttributeImpl) |
| return new Joins.List(from, (Members.ListAttributeImpl) member, jt); |
| else if (member instanceof Members.SetAttributeImpl) |
| return new Joins.Set(from, (Members.SetAttributeImpl) member, jt); |
| else if (member instanceof Members.MapAttributeImpl) |
| return new Joins.Map(from, (Members.MapAttributeImpl) member, jt); |
| return null; |
| } |
| |
| static FromImpl getMembers(PathImpl join, |
| java.util.List<Members.Member> members, |
| java.util.List<JoinType> jts) { |
| PathImpl parent = (PathImpl) join.getParentPath(); |
| Members.Member member = join.getMember(); |
| JoinType jt = ((Join) join).getJoinType(); |
| FromImpl<?, ?> from = null; |
| if (parent instanceof RootImpl) { |
| members.add(member); |
| jts.add(jt); |
| return (FromImpl) parent; |
| } else { |
| from = getMembers(parent, members, jts); |
| } |
| members.add(member); |
| jts.add(jt); |
| return from; |
| } |
| |
| /** |
| * Join a single-valued attribute. |
| * |
| * |
| * @param <Z> type from which joining |
| * @param <X> type of the attribute being joined |
| */ |
| static class SingularJoin<Z,X> extends FromImpl<Z,X> implements Join<Z,X> { |
| private final JoinType joinType; |
| private boolean allowNull = false; |
| |
| public SingularJoin(FromImpl<?,Z> from, Members.SingularAttributeImpl<? super Z, X> member, JoinType jt) { |
| super(from, member, member.getJavaType()); |
| joinType = jt; |
| allowNull = joinType != JoinType.INNER; |
| } |
| |
| @Override |
| public JoinType getJoinType() { |
| return joinType; |
| } |
| |
| @Override |
| public FromImpl<?, Z> getParent() { |
| return (FromImpl<?, Z>) _parent; |
| } |
| |
| @Override |
| public Member<? extends Z, X> getMember() { |
| return (Member<? extends Z, X>) _member; |
| } |
| |
| @Override |
| public Join<Z, X> on(Expression<Boolean> restriction) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Join<Z, X> on(Predicate... restrictions) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Predicate getOn() { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| /** |
| * Return the metamodel attribute corresponding to the join. |
| * @return metamodel attribute type corresponding to the join |
| */ |
| @Override |
| public Attribute<? super Z, ?> getAttribute() { |
| return (Attribute<? super Z, ?> )_member; |
| } |
| |
| @Override |
| public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> c) { |
| ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); |
| org.apache.openjpa.kernel.exps.Path path = null; |
| SubqueryImpl<?> subquery = c.getDelegator(); |
| PathImpl<?,?> parent = getInnermostParentPath(); |
| Value val = c.getRegisteredValue(this); |
| if (val != null) |
| return val; |
| else if (parent.inSubquery(subquery)) { |
| org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); |
| path = factory.newPath(subQ); |
| path.setMetaData(subQ.getMetaData()); |
| path.setSchemaAlias(c.getAlias(this)); |
| path.get(_member.fmd, allowNull); |
| } else { |
| path = (org.apache.openjpa.kernel.exps.Path) _parent.toValue(factory, c); |
| path.get(_member.fmd, allowNull); |
| path.setMetaData(meta); |
| path.setImplicitType(meta.getDescribedType()); |
| } |
| return path; |
| } |
| |
| @Override |
| public org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, |
| CriteriaQueryImpl<?> c) { |
| ClassMetaData meta = _member.fmd.getDeclaredTypeMetaData(); |
| org.apache.openjpa.kernel.exps.Path path = null; |
| SubqueryImpl<?> subquery = c.getDelegator(); |
| PathImpl<?,?> parent = getInnermostParentPath(); |
| org.apache.openjpa.kernel.exps.Expression filter = null; |
| PathImpl<?,?> correlatedParentPath = null; |
| boolean bind = true; |
| java.util.Set<Join<?,?>> corrJoins = null; |
| org.apache.openjpa.kernel.exps.Expression join = null; |
| if (!isCorrelated()) { |
| if (subquery != null) { |
| corrJoins = subquery.getCorrelatedJoins(); |
| org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); |
| if ((!corrJoins.isEmpty() && corrJoins.contains(_parent)) || |
| (corrJoins.isEmpty() && parent.inSubquery(subquery) && _parent.getCorrelatedPath() != null)) { |
| path = factory.newPath(subQ); |
| correlatedParentPath = _parent.getCorrelatedPath(); |
| bind = false; |
| } else { |
| if (c.isRegistered(_parent)) { |
| Value var = c.getRegisteredVariable(_parent); |
| path = factory.newPath(var); |
| } else { |
| path = factory.newPath(subQ); |
| } |
| path.setMetaData(meta); |
| path.get(_member.fmd, allowNull); |
| path.setSchemaAlias(c.getAlias(_parent)); |
| } |
| } else if (c.isRegistered(_parent)) { |
| Value var = c.getRegisteredVariable(_parent); |
| path = factory.newPath(var); |
| path.setMetaData(meta); |
| path.get(_member.fmd, allowNull); |
| } else |
| path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, c); |
| |
| Class<?> type = meta == null ? AbstractExpressionBuilder.TYPE_OBJECT : meta.getDescribedType(); |
| Value var = null; |
| if (bind) { |
| var = factory.newBoundVariable(c.getAlias(this),type); |
| join = factory.bindVariable(var, path); |
| c.registerVariable(this, var, path); |
| } |
| |
| if (!_member.fmd.isTypePC()) { // multi-valued relation |
| setImplicitContainsTypes(path, var, AbstractExpressionBuilder.CONTAINS_TYPE_ELEMENT); |
| join = factory.contains(path, var); |
| } |
| } |
| if (getJoins() != null) { |
| for (Join<?, ?> join1 : getJoins()) { |
| filter = Expressions.and(factory, |
| ((FromImpl<?,?>)join1).toKernelExpression(factory, c), filter); |
| } |
| } |
| org.apache.openjpa.kernel.exps.Expression expr = Expressions.and(factory, join, filter); |
| |
| if (correlatedParentPath == null) { |
| return expr; |
| } else { |
| org.apache.openjpa.kernel.exps.Path parentPath = null; |
| if (corrJoins != null && corrJoins.contains(_parent)) { |
| Value var = getVariableForCorrPath(subquery, correlatedParentPath); |
| parentPath = factory.newPath(var); |
| } else { |
| parentPath = (org.apache.openjpa.kernel.exps.Path)correlatedParentPath.toValue(factory, c); |
| } |
| parentPath.get(_member.fmd, allowNull); |
| parentPath.setSchemaAlias(c.getAlias(correlatedParentPath)); |
| if (c.ctx().getParent() != null && c.ctx().getVariable(parentPath.getSchemaAlias()) == null) |
| parentPath.setSubqueryContext(c.ctx(), parentPath.getSchemaAlias()); |
| |
| path.setMetaData(meta); |
| //filter = bindVariableForKeyPath(path, alias, filter); |
| filter = factory.equal(parentPath, path); |
| return Expressions.and(factory, expr, filter); |
| } |
| } |
| |
| private Value getVariableForCorrPath(SubqueryImpl<?> subquery, PathImpl<?,?> path) { |
| AbstractQuery<?> parent = subquery.getParent(); |
| if (parent instanceof CriteriaQueryImpl) { |
| return ((CriteriaQueryImpl<?>)parent).getRegisteredVariable(path); |
| } |
| Value var = ((SubqueryImpl<?>)parent).getDelegate().getRegisteredVariable(path); |
| if (var != null) |
| return var; |
| return getVariableForCorrPath((SubqueryImpl<?>)parent, path); |
| } |
| |
| /** |
| * Set the implicit types of the given values based on the fact that |
| * the first is supposed to contain the second. |
| */ |
| public void setImplicitContainsTypes(Value val1, Value val2, int op) { |
| if (val1.getType() == AbstractExpressionBuilder.TYPE_OBJECT) { |
| if (op == AbstractExpressionBuilder.CONTAINS_TYPE_ELEMENT) |
| val1.setImplicitType(Collection.class); |
| else |
| val1.setImplicitType(Map.class); |
| } |
| |
| if (val2.getType() == AbstractExpressionBuilder.TYPE_OBJECT && val1 instanceof Path) { |
| FieldMetaData fmd = ((org.apache.openjpa.kernel.exps.Path) val1).last(); |
| ClassMetaData meta; |
| if (fmd != null) { |
| if (op == AbstractExpressionBuilder.CONTAINS_TYPE_ELEMENT || |
| op == AbstractExpressionBuilder.CONTAINS_TYPE_VALUE) { |
| val2.setImplicitType(fmd.getElement().getDeclaredType()); |
| meta = fmd.getElement().getDeclaredTypeMetaData(); |
| if (meta != null) { |
| val2.setMetaData(meta); |
| } |
| } else { |
| val2.setImplicitType(fmd.getKey().getDeclaredType()); |
| meta = fmd.getKey().getDeclaredTypeMetaData(); |
| if (meta != null) { |
| val2.setMetaData(meta); |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public StringBuilder asVariable(AliasContext q) { |
| return new StringBuilder(" " + joinType + " JOIN ").append(super.asVariable(q)); |
| } |
| } |
| |
| /** |
| * Join a plural attribute. |
| * |
| * @param Z type being joined from |
| * @param C Java collection type of the container |
| * @param E type of the element being joined to |
| * |
| */ |
| static abstract class AbstractCollection<Z,C,E> extends FromImpl<Z,E> implements PluralJoin<Z, C, E> { |
| private final JoinType joinType; |
| private boolean allowNull = false; |
| |
| public AbstractCollection(FromImpl<?,Z> from, Members.PluralAttributeImpl<? super Z, C, E> member, |
| JoinType jt) { |
| super(from, member, member.getBindableJavaType()); |
| joinType = jt; |
| allowNull = joinType != JoinType.INNER; |
| } |
| |
| @Override |
| public final JoinType getJoinType() { |
| return joinType; |
| } |
| |
| /** |
| * Gets the parent of this join. |
| */ |
| @Override |
| public final FromImpl<?, Z> getParent() { |
| return (FromImpl<?, Z>) _parent; |
| } |
| |
| @Override |
| public Attribute<? super Z, E> getAttribute() { |
| return (Member<? super Z, E>)_member; |
| } |
| |
| @Override |
| public PluralAttribute<? super Z, C, E> getModel() { |
| return (PluralAttribute<? super Z, C, E>) _member.getType(); |
| } |
| |
| public ClassMetaData getMemberClassMetaData() { |
| return _member.fmd.isElementCollection() |
| ? _member.fmd.getElement().getEmbeddedMetaData() |
| : _member.fmd.getElement().getDeclaredTypeMetaData(); |
| } |
| |
| /** |
| * Convert this path to a kernel path (value). |
| */ |
| @Override |
| public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> c) { |
| org.apache.openjpa.kernel.exps.Path path = null; |
| SubqueryImpl<?> subquery = c.getDelegator(); |
| PathImpl<?,?> parent = getInnermostParentPath(); |
| |
| Value var = c.getRegisteredVariable(this); |
| if (var != null) { |
| path = factory.newPath(var); |
| } else if (parent.inSubquery(subquery)) { |
| org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); |
| path = factory.newPath(subQ); |
| path.setMetaData(subQ.getMetaData()); |
| path.setSchemaAlias(c.getAlias(this)); |
| } else { |
| path = (org.apache.openjpa.kernel.exps.Path) _parent.toValue(factory, c); |
| path.get(_member.fmd, allowNull); |
| } |
| return path; |
| } |
| |
| /** |
| * Convert this path to a join expression. |
| * |
| */ |
| @Override |
| public org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, |
| CriteriaQueryImpl<?> c) { |
| ClassMetaData meta = getMemberClassMetaData(); |
| org.apache.openjpa.kernel.exps.Path path = null; |
| SubqueryImpl<?> subquery = c.getDelegator(); |
| org.apache.openjpa.kernel.exps.Expression filter = null; |
| java.util.Set<Join<?,?>> corrJoins = null; |
| boolean bind = true; |
| org.apache.openjpa.kernel.exps.Expression join = null; |
| PathImpl<?,?> corrJoin = getCorrelatedJoin(this); |
| PathImpl<?,?> corrRoot = getCorrelatedRoot(subquery); |
| |
| PathImpl<?,?> correlatedParentPath = null; |
| if (!isCorrelated()) { |
| if (subquery != null) { |
| corrJoins = subquery.getCorrelatedJoins(); |
| org.apache.openjpa.kernel.exps.Subquery subQ = subquery.getSubQ(); |
| path = factory.newPath(subQ); |
| if ((corrJoin != null || corrRoot != null) && _parent.getCorrelatedPath() != null) { |
| subQ.setSubqAlias(c.getAlias(this)); |
| path = factory.newPath(subQ); |
| correlatedParentPath = _parent.getCorrelatedPath(); |
| bind = false; |
| } else { |
| if (c.isRegistered(_parent)) { |
| Value var = c.getRegisteredVariable(_parent); |
| path = factory.newPath(var); |
| } else { |
| path = factory.newPath(subQ); |
| } |
| path.setMetaData(meta); |
| path.get(_member.fmd, allowNull); |
| path.setSchemaAlias(c.getAlias(_parent)); |
| } |
| } else if (c.isRegistered(_parent)) { |
| Value var = c.getRegisteredVariable(_parent); |
| path = factory.newPath(var); |
| path.setMetaData(meta); |
| path.get(_member.fmd, allowNull); |
| } else { |
| path = (org.apache.openjpa.kernel.exps.Path)toValue(factory, c); |
| } |
| Class<?> type = meta == null ? AbstractExpressionBuilder.TYPE_OBJECT : meta.getDescribedType(); |
| if (bind) { |
| Value var = factory.newBoundVariable(c.getAlias(this), type); |
| join = factory.bindVariable(var, path); |
| c.registerVariable(this, var, path); |
| } |
| } |
| if (getJoins() != null) { |
| for (Join<?, ?> join1 : getJoins()) { |
| filter = Expressions.and(factory, |
| ((FromImpl<?,?>)join1).toKernelExpression(factory, c), filter); |
| } |
| } |
| org.apache.openjpa.kernel.exps.Expression expr = Expressions.and(factory, join, filter); |
| if (correlatedParentPath == null) { |
| return expr; |
| } else { |
| org.apache.openjpa.kernel.exps.Path parentPath = null; |
| if (!corrJoins.isEmpty() && corrJoins.contains(_parent)) { |
| Value var = getVariableForCorrPath(subquery, correlatedParentPath); |
| parentPath = factory.newPath(var); |
| } else { |
| parentPath = (org.apache.openjpa.kernel.exps.Path) correlatedParentPath.toValue(factory, c); |
| } |
| parentPath.get(_member.fmd, allowNull); |
| parentPath.setSchemaAlias(c.getAlias(correlatedParentPath)); |
| if (c.ctx().getParent() != null && c.ctx().getVariable(parentPath.getSchemaAlias()) == null) |
| parentPath.setSubqueryContext(c.ctx(), parentPath.getSchemaAlias()); |
| |
| path.setSchemaAlias(c.getAlias(correlatedParentPath)); |
| path.setMetaData(meta); |
| Class<?> type = meta == null ? AbstractExpressionBuilder.TYPE_OBJECT : meta.getDescribedType(); |
| Value var = factory.newBoundVariable(c.getAlias(this), type); |
| join = factory.bindVariable(var, parentPath); |
| |
| if (_member.fmd.getDeclaredTypeCode() == JavaTypes.MAP) |
| c.registerVariable(this, var, parentPath); |
| |
| if (_member.fmd.isElementCollection()) { |
| filter = Expressions.and(factory, join, filter); |
| } else { |
| filter = factory.equal(parentPath, path); |
| } |
| return Expressions.and(factory, expr, filter); |
| } |
| } |
| |
| private Value getVariableForCorrPath(SubqueryImpl<?> subquery, PathImpl<?,?> path) { |
| AbstractQuery<?> parent = subquery.getParent(); |
| if (parent instanceof CriteriaQueryImpl) { |
| return ((CriteriaQueryImpl<?>)parent).getRegisteredVariable(path); |
| } |
| Value var = ((SubqueryImpl<?>)parent).getDelegate().getRegisteredVariable(path); |
| if (var != null) |
| return var; |
| return getVariableForCorrPath((SubqueryImpl<?>)parent, path); |
| } |
| |
| @Override |
| public StringBuilder asVariable(AliasContext q) { |
| return new StringBuilder(" " + joinType + " JOIN ").append(super.asVariable(q)); |
| } |
| } |
| |
| /** |
| * Join a java.util.Collection<E> type attribute. |
| * |
| * @param <Z> the type from which being joined |
| * @param <E> the type of the the collection attribute elements |
| */ |
| static class Collection<Z,E> extends AbstractCollection<Z,java.util.Collection<E>,E> |
| implements CollectionJoin<Z,E> { |
| public Collection(FromImpl<?,Z> parent, Members.CollectionAttributeImpl<? super Z, E> member, JoinType jt) { |
| super(parent, member, jt); |
| } |
| |
| @Override |
| public CollectionJoin<Z, E> on(Expression<Boolean> restriction) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public CollectionJoin<Z, E> on(Predicate... restrictions) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Predicate getOn() { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public CollectionAttribute<? super Z, E> getModel() { |
| return (CollectionAttribute<? super Z, E>)_member; |
| } |
| } |
| |
| /** |
| * Join a java.util.Set<E> type attribute. |
| * |
| * @param <Z> the type from which being joined |
| * @param <E> the type of the the set attribute elements |
| */ |
| static class Set<Z,E> extends AbstractCollection<Z,java.util.Set<E>,E> |
| implements SetJoin<Z,E> { |
| public Set(FromImpl<?,Z> parent, Members.SetAttributeImpl<? super Z, E> member, JoinType jt) { |
| super(parent, member, jt); |
| } |
| |
| @Override |
| public SetJoin<Z, E> on(Expression<Boolean> restriction) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public SetJoin<Z, E> on(Predicate... restrictions) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Predicate getOn() { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public SetAttribute<? super Z, E> getModel() { |
| return (SetAttribute<? super Z, E>)_member; |
| } |
| } |
| |
| /** |
| * Join a java.util.List<E> type attribute. |
| * |
| * @param <Z> the type from which being joined |
| * @param <E> the type of the the list attribute elements |
| */ |
| |
| static class List<Z,E> extends AbstractCollection<Z,java.util.List<E>,E> |
| implements ListJoin<Z,E> { |
| |
| public List(FromImpl<?,Z> parent, Members.ListAttributeImpl<? super Z, E> member, JoinType jt) { |
| super(parent, member, jt); |
| } |
| |
| @Override |
| public ListJoin<Z, E> on(Expression<Boolean> restriction) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public ListJoin<Z, E> on(Predicate... restrictions) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Predicate getOn() { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public ListAttribute<? super Z, E> getModel() { |
| return (ListAttribute<? super Z, E>)_member; |
| } |
| |
| @Override |
| public Expression<Integer> index() { |
| return new Expressions.Index(this); |
| } |
| } |
| |
| /** |
| * Join a java.util.Map<K,V> type attribute. |
| * |
| * @param <Z> the type from which being joined |
| * @param <K> the type of the the map attribute keys |
| * @param <V> the type of the the map attribute values |
| */ |
| |
| static class Map<Z,K,V> extends AbstractCollection<Z,java.util.Map<K,V>,V> |
| implements MapJoin<Z,K,V> { |
| private KeyJoin<K,V> _keyJoin; |
| |
| public Map(FromImpl<?,Z> parent, Members.MapAttributeImpl<? super Z, K,V> member, JoinType jt) { |
| super(parent, member, jt); |
| } |
| |
| @Override |
| public MapJoin<Z, K, V> on(Expression<Boolean> restriction) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public MapJoin<Z, K, V> on(Predicate... restrictions) { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public Predicate getOn() { |
| throw new UnsupportedOperationException("JPA 2.1"); |
| } |
| |
| @Override |
| public MapAttribute<? super Z, K,V> getModel() { |
| return (MapAttribute<? super Z, K,V>) _member; |
| } |
| |
| public Join<java.util.Map<K, V>, K> joinKey() { |
| return joinKey(JoinType.INNER); |
| } |
| |
| /** |
| * Create a pseudo-attribute of a pseudo-managed type for java.util.Map<K,V> |
| * to represent its keys of type java.util.Set<V>. |
| */ |
| public Join<java.util.Map<K, V>, K> joinKey(JoinType jt) { |
| AbstractManagedType<java.util.Map<K,V>> pseudoOwner = (AbstractManagedType<java.util.Map<K,V>>) |
| _member.owner.model.getType(getModel().getJavaType()); |
| KeyAttributeImpl<java.util.Map<K,V>, K> keyAttr = |
| new Members.KeyAttributeImpl<>(pseudoOwner, _member.fmd); |
| _keyJoin = new KeyJoin<>((FromImpl<?,java.util.Map<K,V>>)this, keyAttr, jt); |
| return _keyJoin; |
| } |
| |
| @Override |
| public Expression<java.util.Map.Entry<K, V>> entry() { |
| return new MapEntry<>(this); |
| } |
| |
| @Override |
| public Path<K> key() { |
| return new MapKey<>(this); |
| } |
| |
| @Override |
| public Path<V> value() { |
| return this; |
| } |
| |
| @Override |
| public org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, |
| CriteriaQueryImpl<?> c) { |
| return (_keyJoin == null) |
| ? super.toKernelExpression(factory, c) |
| : _keyJoin.toKernelExpression(factory, c); |
| } |
| } |
| |
| |
| static class MapKey<Z,K> extends PathImpl<Z,K> { |
| private final Map<?,K,?> map; |
| private final MapAttributeImpl<Z, K, ?> attr; |
| |
| public MapKey(Map<Z,K,?> joinMap){ |
| super(((MapAttribute<Z, K, ?>)joinMap.getAttribute()).getKeyJavaType()); |
| attr = ((MapAttributeImpl<Z, K, ?>)joinMap.getAttribute()); |
| this.map = joinMap; |
| } |
| |
| @Override |
| public Type<?> getType() { |
| return attr.getKeyType(); |
| } |
| |
| /** |
| * Convert this path to a join expression. |
| * |
| */ |
| @Override |
| public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> c) { |
| Value val = c.getRegisteredVariable(map); |
| org.apache.openjpa.kernel.exps.Path path = factory.newPath(val); |
| return factory.getKey(path); |
| } |
| |
| @Override |
| public StringBuilder asValue(AliasContext q) { |
| StringBuilder buffer = new StringBuilder("KEY("); |
| Value var = q.getRegisteredVariable(map); |
| buffer.append(var != null ? var.getName() : map.asValue(q)).append(")"); |
| return buffer; |
| } |
| } |
| |
| static class MapEntry<K,V> extends ExpressionImpl<java.util.Map.Entry<K,V>> { |
| private final Map<?,K,V> map; |
| |
| public MapEntry(Map<?,K,V> joinMap){ |
| super(((MapAttribute)joinMap.getAttribute()).getJavaType()); |
| this.map = joinMap; |
| } |
| |
| /** |
| * Convert this path to a join expression. |
| * |
| */ |
| @Override |
| public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> c) { |
| Value val = c.getRegisteredVariable(map); |
| org.apache.openjpa.kernel.exps.Path path = factory.newPath(val); |
| org.apache.openjpa.kernel.exps.Path var = factory.newPath(val); |
| return factory.mapEntry(path, var); |
| } |
| |
| @Override |
| public StringBuilder asValue(AliasContext q) { |
| StringBuilder buffer = new StringBuilder("ENTRY("); |
| Value var = q.getRegisteredVariable(map); |
| buffer.append(var != null ? var.getName() : map.asValue(q)).append(")"); |
| return buffer; |
| } |
| } |
| |
| /** |
| * A specialized join via key of a java.util.Map<K,V> attribute. |
| * Treats the map key as a pseudo-attribute of type java.util.Set<K> of a pseduo-managed type corresponding |
| * to java.util.Map<K,V>. |
| * |
| * @param <K> the type of the key of the original java.util.Map attribute |
| * @param <V> the type of the value of the original java.util.Map attribute |
| */ |
| static class KeyJoin<K,V> extends Joins.Set<java.util.Map<K, V>, K> { |
| public KeyJoin(FromImpl<?, java.util.Map<K, V>> parent, KeyAttributeImpl<? super java.util.Map<K, V>, K> member, |
| JoinType jt) { |
| super(parent, member, jt); |
| } |
| |
| @Override |
| public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> c) { |
| return factory.getKey(getParent().toValue(factory, c)); |
| } |
| } |
| } |