Skip to contentMethod: getPluralAttributes()
1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jopa.model.metamodel;
19:
20: import cz.cvut.kbss.jopa.exception.AbstractTypeException;
21:
22: import java.util.Collections;
23: import java.util.HashMap;
24: import java.util.HashSet;
25: import java.util.Map;
26: import java.util.Objects;
27: import java.util.Set;
28: import java.util.stream.Collectors;
29:
30: /**
31: * Instances of the type AbstractIdentifiableType represent entity or mapped superclass types which can be queried for
32: * attributes, subtypes and so on.
33: *
34: * @param <X> Entity type being represented by this instance
35: */
36:
37: public abstract class AbstractIdentifiableType<X> implements IdentifiableType<X> {
38:
39: private final Class<X> javaType;
40:
41: private Identifier<X, ?> identifier;
42:
43: private Set<AbstractIdentifiableType<? super X>> supertypes = new HashSet<>();
44:
45: /// AIT which is superclass of this AIT, and from which we inherit attributes
46: private AbstractIdentifiableType<? super X> classSupertype;
47:
48: private Set<AbstractIdentifiableType<? extends X>> subtypes;
49:
50: private TypesSpecification<X, ?> directTypes;
51:
52: private PropertiesSpecification<X, ?, ?, ?> properties;
53:
54: private final Map<String, AbstractAttribute<X, ?>> declaredAttributes = new HashMap<>();
55:
56: private final Map<String, AbstractQueryAttribute<X, ?>> declaredQueryAttributes = new HashMap<>();
57:
58: private EntityLifecycleListenerManager lifecycleListenerManager = EntityLifecycleListenerManager.empty();
59:
60: AbstractIdentifiableType(Class<X> javaType) {
61: this.javaType = javaType;
62: }
63:
64: void addDeclaredAttribute(final String name, final AbstractAttribute<X, ?> a) {
65: declaredAttributes.put(name, a);
66: }
67:
68: void addDeclaredQueryAttribute(final String name, final AbstractQueryAttribute<X, ?> a) {
69: declaredQueryAttributes.put(name, a);
70: }
71:
72: /**
73: * Set supertypes of this instance, and for all given supertypes add this as their subtype. This method should not
74: * be called multiple times on one instance.
75: *
76: * @param supertypes Supertypes to set
77: */
78: void setSupertypes(Set<AbstractIdentifiableType<? super X>> supertypes) {
79: assert supertypes != null;
80: this.supertypes = supertypes;
81:
82: supertypes.forEach(supertype -> supertype.addSubtype(this));
83: /// find non-abstract parent (class), and use it later for finding attributes, as attributes can be only in AITs that represent classes
84: supertypes.stream().filter(ait -> !ait.getJavaType().isInterface()).findAny()
85: .ifPresent(clsSupertype -> this.classSupertype = clsSupertype);
86: }
87:
88: private void addSubtype(AbstractIdentifiableType<? extends X> subtype) {
89: if (subtypes == null) {
90: this.subtypes = new HashSet<>(2);
91: }
92: subtypes.add(subtype);
93: }
94:
95: void addDirectTypes(TypesSpecification<X, ?> a) {
96: this.directTypes = a;
97: }
98:
99: void addOtherProperties(PropertiesSpecification<X, ?, ?, ?> a) {
100: this.properties = a;
101: }
102:
103: public void setIdentifier(final Identifier<X, ?> identifier) {
104: this.identifier = identifier;
105: }
106:
107: @Override
108: public boolean hasSingleIdAttribute() {
109: return true; // We do not support id classes
110: }
111:
112: @Override
113: public <Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> type) {
114: // TODO
115: throw new UnsupportedOperationException();
116: }
117:
118: @Override
119: public Set<AbstractIdentifiableType<? super X>> getSupertypes() {
120: return supertypes;
121: }
122:
123: /**
124: * Whether this managed type has any managed subtypes (entities or mapped superclasses).
125: *
126: * @return {@code true} when managed subtypes exist, {@code false} otherwise
127: */
128: public boolean hasSubtypes() {
129: return subtypes != null;
130: }
131:
132: /**
133: * Whether the Java type represented by this type is an abstract class.
134: *
135: * @return {@code true} if the represented Java type is abstract, {@code false} otherwise
136: */
137: public abstract boolean isAbstract();
138:
139: /**
140: * Gets the Java type represented by the metamodel instance that can be instantiated.
141: * <p>
142: * The purpose of this method is mainly to return the generated subclass of {@link #getJavaType()} that is used for
143: * instantiation.
144: *
145: * @return Instantiable Java type
146: */
147: public Class<? extends X> getInstantiableJavaType() {
148: throw new AbstractTypeException("Type " + getJavaType() + " is an abstract type and cannot be instantiated!");
149: }
150:
151: public Set<AbstractIdentifiableType<? extends X>> getSubtypes() {
152: return subtypes != null ? Collections.unmodifiableSet(subtypes) : Collections.emptySet();
153: }
154:
155: @Override
156: public <Y> SingularAttribute<? super X, Y> getVersion(Class<Y> type) {
157: // TODO
158: throw new UnsupportedOperationException();
159: }
160:
161: @Override
162: public boolean hasVersionAttribute() {
163: return false;
164: }
165:
166: @Override
167: public Set<Attribute<? super X, ?>> getAttributes() {
168: final Set<Attribute<? super X, ?>> attributes = new HashSet<>(declaredAttributes.values());
169: if (classSupertype != null) {
170: attributes.addAll(classSupertype.getAttributes());
171: }
172:
173: return attributes;
174: }
175:
176: @Override
177: public Set<QueryAttribute<? super X, ?>> getQueryAttributes() {
178: final Set<QueryAttribute<? super X, ?>> queryAttributes = new HashSet<>(declaredQueryAttributes.values());
179:
180: if (classSupertype != null) {
181: queryAttributes.addAll(classSupertype.getQueryAttributes());
182: }
183: return queryAttributes;
184: }
185:
186: @Override
187: public AbstractAttribute<? super X, ?> getAttribute(String name) {
188: Objects.requireNonNull(name);
189: if (declaredAttributes.containsKey(name)) {
190: return declaredAttributes.get(name);
191: }
192:
193: if (classSupertype != null) {
194: return classSupertype.getAttribute(name);
195: }
196: throw attributeMissing(name, false);
197: }
198:
199: protected IllegalArgumentException attributeMissing(String name, boolean declared) {
200: return new IllegalArgumentException("Attribute " + name + " is not " + (declared ? "declared" : "present") + " in type " + this);
201: }
202:
203: @Override
204: public boolean hasQueryAttribute(String name) {
205: Objects.requireNonNull(name);
206: if (declaredQueryAttributes.containsKey(name)) {
207: return true;
208: }
209:
210: if (classSupertype != null) {
211: return classSupertype.hasQueryAttribute(name);
212: }
213: return false;
214: }
215:
216: @Override
217: public AbstractQueryAttribute<? super X, ?> getQueryAttribute(String name) {
218: Objects.requireNonNull(name);
219: if (declaredQueryAttributes.containsKey(name)) {
220: return declaredQueryAttributes.get(name);
221: }
222: if (classSupertype != null) {
223: return classSupertype.getQueryAttribute(name);
224: }
225:
226: throw attributeMissing(name, false);
227: }
228:
229: @Override
230: public CollectionAttribute<? super X, ?> getCollection(String name) {
231: return getCollection(name, Object.class);
232: }
233:
234: @Override
235: public <E> CollectionAttribute<? super X, E> getCollection(String name, Class<E> elementType) {
236: return getPluralAttribute("Collection", name, elementType, CollectionAttribute.class);
237: }
238:
239: private <E, R extends PluralAttribute<? super X, ?, E>> R getPluralAttribute(String type, String name,
240: Class<E> elementType,
241: Class<R> attType) {
242: final Attribute<? super X, ?> a = getAttribute(name);
243:
244: checkPluralAttribute(a, type, name, elementType, attType, false);
245: return attType.cast(a);
246: }
247:
248: private <E, R extends PluralAttribute<? super X, ?, E>> void checkPluralAttribute(Attribute<? super X, ?> att,
249: String type, String name,
250: Class<E> elementType,
251: Class<R> attType,
252: boolean declared) {
253: if (!attType.isAssignableFrom(att.getClass())) {
254: throw pluralAttNotFound(type, name, elementType, declared);
255: }
256:
257: final PluralAttribute<? super X, ?, E> colAtt = (PluralAttribute<? super X, ?, E>) att;
258: if (!elementType.isAssignableFrom(colAtt.getBindableJavaType())) {
259: throw pluralAttNotFound(type, name, elementType, declared);
260: }
261: }
262:
263: private IllegalArgumentException pluralAttNotFound(String type, String name, Class<?> elementType,
264: boolean declared) {
265: return new IllegalArgumentException(type + " attribute " + name + " with element type " + elementType + " is not " + (declared ? "declared" : "present") + " in type " + this);
266: }
267:
268: @Override
269: public <E> ListAttribute<? super X, E> getList(String name, Class<E> elementType) {
270: return getPluralAttribute("List", name, elementType, ListAttribute.class);
271: }
272:
273: @Override
274: public ListAttribute<? super X, ?> getList(String name) {
275: return getList(name, Object.class);
276: }
277:
278: @Override
279: public <K, V> MapAttribute<? super X, K, V> getMap(String name, Class<K> keyType, Class<V> valueType) {
280: throw new UnsupportedOperationException();
281: }
282:
283: @Override
284: public MapAttribute<? super X, ?, ?> getMap(String name) {
285: return getMap(name, Object.class, Object.class);
286: }
287:
288: @Override
289: public <E> SetAttribute<? super X, E> getSet(String name, Class<E> elementType) {
290: return getPluralAttribute("Set", name, elementType, SetAttribute.class);
291: }
292:
293: @Override
294: public SetAttribute<? super X, ?> getSet(String name) {
295: return getSet(name, Object.class);
296: }
297:
298: @Override
299: public Set<PluralAttribute<? super X, ?, ?>> getPluralAttributes() {
300: final Set<PluralAttribute<? super X, ?, ?>> plurals = new HashSet<>(getDeclaredPluralAttributes());
301:• if (classSupertype != null) {
302: plurals.addAll(classSupertype.getPluralAttributes());
303: }
304:
305: return plurals;
306: }
307:
308: @Override
309: public Set<SingularAttribute<? super X, ?>> getSingularAttributes() {
310: final Set<SingularAttribute<? super X, ?>> singulars = new HashSet<>(getDeclaredSingularAttributes());
311: if (classSupertype != null) {
312: singulars.addAll(classSupertype.getSingularAttributes());
313: }
314: return singulars;
315: }
316:
317: @Override
318: public <Y> SingularAttribute<? super X, Y> getSingularAttribute(String name, Class<Y> type) {
319: final Attribute<? super X, ?> a = getAttribute(name);
320:
321: if (a.isCollection()) {
322: throw singularAttNotFound(name, type, false);
323: }
324: assert a instanceof SingularAttribute;
325: if (!type.isAssignableFrom(a.getJavaType())) {
326: throw singularAttNotFound(name, type, false);
327: }
328:
329: return (SingularAttribute<? super X, Y>) a;
330: }
331:
332: private IllegalArgumentException singularAttNotFound(String name, Class<?> type, boolean declared) {
333: return new IllegalArgumentException("Singular attribute " + name + " of type " + type + " is not " + (declared ? "declared" : "present") + " in type " + this);
334: }
335:
336: @Override
337: public SingularAttribute<? super X, ?> getSingularAttribute(String name) {
338: return getSingularAttribute(name, Object.class);
339: }
340:
341: @Override
342: public Set<Attribute<X, ?>> getDeclaredAttributes() {
343: return new HashSet<>(declaredAttributes.values());
344: }
345:
346: @Override
347: public Set<PluralAttribute<X, ?, ?>> getDeclaredPluralAttributes() {
348: return declaredAttributes.values().stream().filter(Attribute::isCollection)
349: .map(a -> (PluralAttribute<X, ?, ?>) a).collect(Collectors.toSet());
350: }
351:
352: @Override
353: public Set<SingularAttribute<X, ?>> getDeclaredSingularAttributes() {
354: return declaredAttributes.values().stream().filter(att -> !att.isCollection())
355: .map(a -> (SingularAttribute<X, ?>) a).collect(Collectors.toSet());
356: }
357:
358: @Override
359: public AbstractAttribute<X, ?> getDeclaredAttribute(String name) {
360: if (declaredAttributes.containsKey(name)) {
361: return declaredAttributes.get(name);
362: }
363: throw attributeMissing(name, true);
364: }
365:
366: @Override
367: public <E> CollectionAttribute<X, E> getDeclaredCollection(String name, Class<E> elementType) {
368: return getDeclaredPluralAttribute("Collection", name, elementType, CollectionAttribute.class);
369: }
370:
371: private <E, R extends PluralAttribute<? super X, ?, E>> R getDeclaredPluralAttribute(String type, String name,
372: Class<E> elementType,
373: Class<R> attType) {
374: final Attribute<? super X, ?> a = getDeclaredAttribute(name);
375:
376: checkPluralAttribute(a, type, name, elementType, attType, true);
377: return attType.cast(a);
378: }
379:
380: @Override
381: public CollectionAttribute<X, ?> getDeclaredCollection(String name) {
382: return getDeclaredCollection(name, Object.class);
383: }
384:
385: @Override
386: public <E> ListAttribute<X, E> getDeclaredList(String name, Class<E> elementType) {
387: return getDeclaredPluralAttribute("List", name, elementType, ListAttribute.class);
388: }
389:
390: @Override
391: public ListAttribute<X, ?> getDeclaredList(String name) {
392: return getDeclaredList(name, Object.class);
393: }
394:
395: @Override
396: public <K, V> MapAttribute<X, K, V> getDeclaredMap(String name, Class<K> keyType, Class<V> valueType) {
397: throw new UnsupportedOperationException();
398: }
399:
400: @Override
401: public MapAttribute<X, ?, ?> getDeclaredMap(String name) {
402: return getDeclaredMap(name, Object.class, Object.class);
403: }
404:
405: @Override
406: public <E> SetAttribute<X, E> getDeclaredSet(String name, Class<E> elementType) {
407: return getDeclaredPluralAttribute("Set", name, elementType, SetAttribute.class);
408: }
409:
410: @Override
411: public SetAttribute<X, ?> getDeclaredSet(String name) {
412: return getDeclaredSet(name, Object.class);
413: }
414:
415: @Override
416: public <Y> SingularAttribute<X, Y> getDeclaredSingularAttribute(String name, Class<Y> type) {
417: final Attribute<X, ?> a = getDeclaredAttribute(name);
418:
419: if (a.isCollection()) {
420: throw singularAttNotFound(name, type, true);
421: }
422: if (!type.isAssignableFrom(a.getJavaType())) {
423: throw singularAttNotFound(name, type, true);
424: }
425:
426: return (SingularAttribute<X, Y>) a;
427: }
428:
429: @Override
430: public SingularAttribute<X, ?> getDeclaredSingularAttribute(String name) {
431: return getDeclaredSingularAttribute(name, Object.class);
432: }
433:
434: @Override
435: public TypesSpecification<? super X, ?> getTypes() {
436: if (directTypes != null) {
437: return directTypes;
438: }
439:
440: return classSupertype != null ? classSupertype.getTypes() : null;
441: }
442:
443: @Override
444: public PropertiesSpecification<? super X, ?, ?, ?> getProperties() {
445: if (properties != null) {
446: return properties;
447: }
448:
449: return classSupertype != null ? classSupertype.getProperties() : null;
450: }
451:
452: @Override
453: public Set<FieldSpecification<? super X, ?>> getFieldSpecifications() {
454: final Set<FieldSpecification<? super X, ?>> specs = new HashSet<>(getAttributes());
455: specs.addAll(getQueryAttributes());
456: final TypesSpecification<? super X, ?> types = getTypes();
457: if (types != null) {
458: specs.add(types);
459: }
460: final PropertiesSpecification<? super X, ?, ?, ?> props = getProperties();
461: if (props != null) {
462: specs.add(props);
463: }
464: specs.add(getIdentifier());
465: return specs;
466: }
467:
468: @Override
469: public FieldSpecification<? super X, ?> getFieldSpecification(String fieldName) {
470: if (declaredAttributes.containsKey(fieldName)) {
471: return declaredAttributes.get(fieldName);
472: }
473: if (declaredQueryAttributes.containsKey(fieldName)) {
474: return declaredQueryAttributes.get(fieldName);
475: }
476: if (directTypes != null && directTypes.getName().equals(fieldName)) {
477: return directTypes;
478: } else if (properties != null && properties.getName().equals(fieldName)) {
479: return properties;
480: } else if (identifier != null && identifier.getName().equals(fieldName)) {
481: return identifier;
482: }
483: if (classSupertype != null) {
484: return classSupertype.getFieldSpecification(fieldName);
485: }
486:
487: throw new IllegalArgumentException("Field " + fieldName + " is not present in type " + this);
488: }
489:
490: @Override
491: public Identifier<? super X, ?> getIdentifier() {
492: if (identifier != null) {
493: return identifier;
494: }
495:
496: if (classSupertype != null) {
497: return classSupertype.getIdentifier();
498: }
499:
500: // This shouldn't happen, because every entity has to contain an identifier, otherwise metamodel building fails
501: throw new IllegalArgumentException("Identifier attribute is not present in type " + this);
502: }
503:
504: @Override
505: public Class<X> getJavaType() {
506: return javaType;
507: }
508:
509: public EntityLifecycleListenerManager getLifecycleListenerManager() {
510: return lifecycleListenerManager;
511: }
512:
513: public void setLifecycleListenerManager(EntityLifecycleListenerManager lifecycleListenerManager) {
514: this.lifecycleListenerManager = lifecycleListenerManager;
515: }
516: }