Skip to contentMethod: getEntityClass(Class)
1: /**
2: * Copyright (C) 2020 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model.metamodel;
16:
17: import cz.cvut.kbss.jopa.exception.MetamodelInitializationException;
18: import cz.cvut.kbss.jopa.loaders.PersistenceUnitClassFinder;
19: import cz.cvut.kbss.jopa.model.annotations.Inheritance;
20: import cz.cvut.kbss.jopa.query.NamedQueryManager;
21: import cz.cvut.kbss.jopa.query.ResultSetMappingManager;
22: import cz.cvut.kbss.jopa.query.mapper.ResultSetMappingProcessor;
23: import cz.cvut.kbss.jopa.utils.Constants;
24: import org.slf4j.Logger;
25: import org.slf4j.LoggerFactory;
26:
27: import java.lang.reflect.Field;
28: import java.util.*;
29:
30: public class MetamodelBuilder {
31:
32: private static final Logger LOG = LoggerFactory.getLogger(MetamodelBuilder.class);
33:
34: private final NamedNativeQueryProcessor queryProcessor = new NamedNativeQueryProcessor();
35: private final ResultSetMappingProcessor mappingProcessor;
36:
37: private final Map<Class<?>, AbstractIdentifiableType<?>> typeMap = new HashMap<>();
38: private final Set<Class<?>> inferredClasses = new HashSet<>();
39:
40: private final ConverterResolver converterResolver = new ConverterResolver(new Converters());
41:
42: public MetamodelBuilder() {
43: this.mappingProcessor = new ResultSetMappingProcessor(this);
44: }
45:
46: /**
47: * Builds persistence unit metamodel based on classes discovered by the specified class finder.
48: *
49: * @param classFinder Holder of information about classes relevant for persistence unit building
50: */
51: public void buildMetamodel(PersistenceUnitClassFinder classFinder) {
52: classFinder.getEntities().forEach(this::processOWLClass);
53: classFinder.getResultSetMappings().forEach(mappingProcessor::buildMapper);
54: }
55:
56: private <X> void processOWLClass(final Class<X> cls) {
57: if (typeMap.containsKey(cls)) {
58: return;
59: }
60:
61: LOG.debug("Processing OWL class: {}", cls);
62:
63: final TypeBuilderContext<X> et = ManagedClassProcessor.processManagedType(cls);
64: et.setConverterResolver(converterResolver);
65:
66: processManagedType(et);
67: }
68:
69: private <X> void processManagedType(TypeBuilderContext<X> context) {
70: final AbstractIdentifiableType<X> type = context.getType();
71: final Class<X> cls = type.getJavaType();
72: typeMap.put(cls, type);
73:
74: final AbstractIdentifiableType<? super X> supertype = processSupertypes(cls);
75: if (supertype != null) {
76: type.setSupertype(supertype);
77: }
78: type.setLifecycleListenerManager(new EntityLifecycleCallbackResolver(type).resolve());
79:
80: final ClassFieldMetamodelProcessor<X> fieldProcessor = new ClassFieldMetamodelProcessor<>(context, this);
81:
82: for (Field f : cls.getDeclaredFields()) {
83: fieldProcessor.processField(f);
84: }
85:
86: if (type.getPersistenceType() == Type.PersistenceType.ENTITY) {
87: try {
88: type.getIdentifier();
89: } catch (IllegalArgumentException e) {
90: throw new MetamodelInitializationException("Missing identifier field in entity " + cls);
91: }
92: resolveInheritanceType((EntityTypeImpl<X>) type);
93: }
94:
95: queryProcessor.processClass(cls);
96: }
97:
98: private <X> AbstractIdentifiableType<? super X> processSupertypes(Class<X> cls) {
99: final Class<? super X> managedSupertype = ManagedClassProcessor.getManagedSupertype(cls);
100: if (managedSupertype != null) {
101: if (typeMap.containsKey(managedSupertype)) {
102: return (AbstractIdentifiableType<? super X>) typeMap.get(managedSupertype);
103: }
104: final TypeBuilderContext<? super X> context = ManagedClassProcessor.processManagedType(managedSupertype);
105: context.setConverterResolver(converterResolver);
106: processManagedType(context);
107: return context.getType();
108: }
109: return null;
110: }
111:
112: private static <X> void resolveInheritanceType(EntityTypeImpl<X> et) {
113: final Class<X> cls = et.getJavaType();
114: final Inheritance inheritance = cls.getDeclaredAnnotation(Inheritance.class);
115: if (inheritance != null) {
116: if (et.getSupertype() != null &&
117: et.getSupertype().getPersistenceType() != Type.PersistenceType.MAPPED_SUPERCLASS) {
118: throw new MetamodelInitializationException("Class " + cls +
119: " cannot declare inheritance strategy, because it already inherits it from its supertype.");
120: }
121: et.setInheritanceType(inheritance.strategy());
122: } else {
123: et.setInheritanceType(Constants.DEFAULT_INHERITANCE_TYPE);
124: }
125: }
126:
127: public Map<Class<?>, ManagedType<?>> getTypeMap() {
128: return Collections.unmodifiableMap(typeMap);
129: }
130:
131: public <X> AbstractIdentifiableType<X> entity(Class<X> cls) {
132: return (AbstractIdentifiableType<X>) typeMap.get(cls);
133: }
134:
135: public Map<Class<?>, EntityType<?>> getEntities() {
136: final Map<Class<?>, EntityType<?>> map = new HashMap<>();
137: typeMap.entrySet().stream().filter(e -> e.getValue().getPersistenceType() == Type.PersistenceType.ENTITY)
138: .forEach(e -> map.put(e.getKey(), (EntityType<?>) e.getValue()));
139: return map;
140: }
141:
142: public Set<Class<?>> getInferredClasses() {
143: return Collections.unmodifiableSet(inferredClasses);
144: }
145:
146: public NamedQueryManager getNamedQueryManager() {
147: return queryProcessor.getQueryManager();
148: }
149:
150: public ResultSetMappingManager getResultSetMappingManager() {
151: return mappingProcessor.getManager();
152: }
153:
154: void addInferredClass(Class<?> cls) {
155: inferredClasses.add(cls);
156: }
157:
158: @SuppressWarnings("unchecked")
159: <X> ManagedType<X> getEntityClass(Class<X> cls) {
160:• if (!typeMap.containsKey(cls)) {
161: processOWLClass(cls);
162: }
163: return (ManagedType<X>) typeMap.get(cls);
164: }
165: }