use of com.blazebit.persistence.view.impl.metamodel.MappingConstructorImpl in project blaze-persistence by Blazebit.
the class ProxyFactory method createProxyClass.
@SuppressWarnings("unchecked")
private <T> Class<? extends T> createProxyClass(EntityViewManager entityViewManager, ManagedViewTypeImplementor<T> managedViewType, boolean unsafe) {
ViewType<T> viewType = managedViewType instanceof ViewType<?> ? (ViewType<T>) managedViewType : null;
Class<?> clazz = managedViewType.getJavaType();
String suffix = unsafe ? "unsafe_" : "";
String baseName = clazz.getName();
String proxyClassName = baseName + "_$$_javassist_entityview_" + suffix;
CtClass cc = pool.makeClass(proxyClassName);
CtClass superCc;
ClassPath classPath = new ClassClassPath(clazz);
pool.insertClassPath(classPath);
try {
addReadsModule(clazz, clazz, ProxyFactory.class);
superCc = pool.get(getProxyBase(clazz).getName());
if (clazz.isInterface()) {
cc.addInterface(superCc);
} else {
cc.setSuperclass(superCc);
}
boolean dirtyChecking = false;
CtField dirtyField = null;
CtField readOnlyParentsField = null;
CtField parentField = null;
CtField parentIndexField = null;
CtField initialStateField = null;
CtField mutableStateField = null;
CtMethod markDirtyStub = null;
long alwaysDirtyMask = 0L;
cc.addInterface(pool.get(EntityViewProxy.class.getName()));
addGetJpaManagedClass(cc, managedViewType.getEntityClass());
addGetJpaManagedBaseClass(cc, getJpaManagedBaseClass(managedViewType));
addGetEntityViewClass(cc, clazz);
addIsNewAndReferenceMembers(managedViewType, cc, clazz);
CtField evmField = new CtField(pool.get(EntityViewManager.class.getName()), SerializableEntityViewManager.EVM_FIELD_NAME, cc);
evmField.setModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.VOLATILE);
cc.addField(evmField);
cc.addField(CtField.make("public static final " + EntityViewManager.class.getName() + " " + SerializableEntityViewManager.SERIALIZABLE_EVM_FIELD_NAME + " = new " + SerializableEntityViewManager.class.getName() + "(" + cc.getName() + ".class, " + cc.getName() + "#" + SerializableEntityViewManager.EVM_FIELD_NAME + ");", cc));
if (managedViewType.isUpdatable() || managedViewType.isCreatable()) {
if (true || managedViewType.getFlushMode() == FlushMode.LAZY || managedViewType.getFlushMode() == FlushMode.PARTIAL) {
cc.addInterface(pool.get(DirtyStateTrackable.class.getName()));
initialStateField = new CtField(pool.get(Object[].class.getName()), "$$_initialState", cc);
initialStateField.setModifiers(getModifiers(false));
cc.addField(initialStateField);
addGetter(cc, initialStateField, "$$_getInitialState");
}
cc.addInterface(pool.get(MutableStateTrackable.class.getName()));
cc.addInterface(pool.get(DirtyTracker.class.getName()));
mutableStateField = new CtField(pool.get(Object[].class.getName()), "$$_mutableState", cc);
mutableStateField.setModifiers(getModifiers(false));
cc.addField(mutableStateField);
CtField initializedField = new CtField(CtClass.booleanType, "$$_initialized", cc);
initializedField.setModifiers(getModifiers(false));
cc.addField(initializedField);
readOnlyParentsField = new CtField(pool.get(List.class.getName()), "$$_readOnlyParents", cc);
readOnlyParentsField.setModifiers(getModifiers(true));
readOnlyParentsField.setGenericSignature(Descriptor.of(List.class.getName()) + "<" + Descriptor.of(Object.class.getName()) + ">;");
cc.addField(readOnlyParentsField);
parentField = new CtField(pool.get(DirtyTracker.class.getName()), "$$_parent", cc);
parentField.setModifiers(getModifiers(true));
cc.addField(parentField);
parentIndexField = new CtField(CtClass.intType, "$$_parentIndex", cc);
parentIndexField.setModifiers(getModifiers(true));
cc.addField(parentIndexField);
dirtyChecking = true;
addGetter(cc, mutableStateField, "$$_getMutableState");
addGetter(cc, readOnlyParentsField, "$$_getReadOnlyParents");
addGetter(cc, parentField, "$$_getParent");
addGetter(cc, parentIndexField, "$$_getParentIndex");
addAddReadOnlyParent(cc, readOnlyParentsField, parentField);
addRemoveReadOnlyParent(cc, readOnlyParentsField);
addSetParent(cc, parentField, parentIndexField);
addHasParent(cc, parentField);
addUnsetParent(cc, parentField, parentIndexField, readOnlyParentsField);
markDirtyStub = addMarkDirtyStub(cc);
}
Set<MethodAttribute<? super T, ?>> attributes = new LinkedHashSet<>(managedViewType.getAttributes());
CtField[] attributeFields = new CtField[attributes.size()];
CtClass[] attributeTypes = new CtClass[attributes.size()];
Map<String, CtField> fieldMap = new HashMap<>(attributes.size());
int i = 0;
// Create the id field
AbstractMethodAttribute<? super T, ?> idAttribute = null;
CtField idField = null;
AbstractMethodAttribute<? super T, ?> versionAttribute = null;
final AbstractMethodAttribute<?, ?>[] methodAttributes = new AbstractMethodAttribute[attributeFields.length];
if (viewType != null) {
idAttribute = (AbstractMethodAttribute<? super T, ?>) viewType.getIdAttribute();
versionAttribute = (AbstractMethodAttribute<? super T, ?>) viewType.getVersionAttribute();
idField = addMembersForAttribute(idAttribute, clazz, cc, null, false, true, mutableStateField != null);
fieldMap.put(idAttribute.getName(), idField);
attributeFields[0] = idField;
attributeTypes[0] = idField.getType();
methodAttributes[0] = idAttribute;
attributes.remove(idAttribute);
i = 1;
if (mutableStateField != null) {
addSetId(cc, idField);
}
} else if (mutableStateField != null) {
addSetId(cc, null);
}
addGetter(cc, idField, "$$_getId", Object.class);
int mutableAttributeCount = 0;
for (MethodAttribute<?, ?> attribute : attributes) {
AbstractMethodAttribute<?, ?> methodAttribute = (AbstractMethodAttribute<?, ?>) attribute;
if (NEEDS_READS_INJECTOR) {
for (Class<?> allowedSubtype : attribute.getAllowedSubtypes()) {
addReadsModule(clazz, clazz, allowedSubtype);
}
for (Type<?> allowedSubtype : attribute.getReadOnlyAllowedSubtypes()) {
addReadsModule(clazz, clazz, allowedSubtype.getJavaType());
}
for (Type<?> allowedSubtype : attribute.getPersistCascadeAllowedSubtypes()) {
addReadsModule(clazz, clazz, allowedSubtype.getJavaType());
}
for (Type<?> allowedSubtype : attribute.getUpdateCascadeAllowedSubtypes()) {
addReadsModule(clazz, clazz, allowedSubtype.getJavaType());
}
}
boolean forceMutable = mutableStateField != null && methodAttribute == versionAttribute;
CtField attributeField = addMembersForAttribute(methodAttribute, clazz, cc, mutableStateField, dirtyChecking, false, forceMutable);
fieldMap.put(attribute.getName(), attributeField);
attributeFields[i] = attributeField;
attributeTypes[i] = attributeField.getType();
methodAttributes[i] = methodAttribute;
if (methodAttribute.hasDirtyStateIndex()) {
mutableAttributeCount++;
}
i++;
}
if (mutableStateField != null) {
if (versionAttribute != null) {
CtField versionField = fieldMap.get(versionAttribute.getName());
addGetter(cc, versionField, "$$_getVersion", Object.class);
addSetVersion(cc, versionField);
} else {
addGetter(cc, null, "$$_getVersion", Object.class);
addSetVersion(cc, null);
}
} else {
addGetter(cc, null, "$$_getVersion", Object.class);
}
if (dirtyChecking) {
addReplaceAttribute(cc, methodAttributes);
cc.removeMethod(markDirtyStub);
if (mutableAttributeCount > 64) {
throw new IllegalArgumentException("Support for more than 64 mutable attributes per view is not yet implemented! " + viewType.getJavaType().getName() + " has " + mutableAttributeCount);
} else {
dirtyField = new CtField(CtClass.longType, "$$_dirty", cc);
dirtyField.setModifiers(getModifiers(true));
cc.addField(dirtyField);
boolean allSupportDirtyTracking = true;
boolean[] supportsDirtyTracking = new boolean[mutableAttributeCount];
int mutableAttributeIndex = 0;
for (int j = 0; j < methodAttributes.length; j++) {
if (methodAttributes[j] != null && methodAttributes[j].hasDirtyStateIndex()) {
if (supportsDirtyTracking(methodAttributes[j])) {
supportsDirtyTracking[mutableAttributeIndex++] = true;
} else {
allSupportDirtyTracking = false;
alwaysDirtyMask |= 1 << mutableAttributeIndex;
supportsDirtyTracking[mutableAttributeIndex++] = false;
}
}
}
addIsDirty(cc, dirtyField, allSupportDirtyTracking);
addIsDirtyAttribute(cc, dirtyField, supportsDirtyTracking, allSupportDirtyTracking);
addMarkDirty(cc, dirtyField);
addUnmarkDirty(cc, dirtyField, alwaysDirtyMask);
addSetDirty(cc, dirtyField, alwaysDirtyMask);
addResetDirty(cc, dirtyField, alwaysDirtyMask);
addGetDirty(cc, dirtyField);
addGetSimpleDirty(cc, dirtyField);
addCopyDirty(cc, dirtyField, supportsDirtyTracking, allSupportDirtyTracking);
}
}
createEqualsHashCodeMethods(viewType, managedViewType, cc, superCc, attributeFields, idField);
cc.addMethod(createToString(managedViewType, cc, viewType != null, attributeFields));
createSpecialMethods(managedViewType, cc, cc);
createSerializationSubclass(managedViewType, cc);
Set<MappingConstructorImpl<T>> constructors = (Set<MappingConstructorImpl<T>>) (Set<?>) managedViewType.getConstructors();
boolean hasEmptyConstructor = managedViewType.hasEmptyConstructor();
if (hasEmptyConstructor) {
// Create constructor for create models
cc.addConstructor(createCreateConstructor(entityViewManager, managedViewType, cc, attributeFields, attributeTypes, idField, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, alwaysDirtyMask, unsafe));
}
boolean addedReferenceConstructor = false;
if (idField != null && hasEmptyConstructor) {
// Id only constructor for reference models
cc.addConstructor(createReferenceConstructor(entityViewManager, managedViewType, cc, attributeFields, idField, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, alwaysDirtyMask, unsafe));
addedReferenceConstructor = true;
}
if (shouldAddDefaultConstructor(hasEmptyConstructor, addedReferenceConstructor, attributeFields)) {
cc.addConstructor(createNormalConstructor(entityViewManager, managedViewType, null, cc, attributeFields, attributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, alwaysDirtyMask, unsafe));
cc.addConstructor(createTupleConstructor(managedViewType, null, cc, attributeFields.length, attributeFields.length, attributeFields, attributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, false, alwaysDirtyMask, unsafe));
cc.addConstructor(createTupleConstructor(managedViewType, null, cc, attributeFields.length, attributeFields.length, attributeFields, attributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, true, alwaysDirtyMask, unsafe));
} else if (hasEmptyConstructor) {
cc.addConstructor(createTupleConstructor(managedViewType, null, cc, attributeFields.length, attributeFields.length, attributeFields, attributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, false, alwaysDirtyMask, unsafe));
cc.addConstructor(createTupleConstructor(managedViewType, null, cc, attributeFields.length, attributeFields.length, attributeFields, attributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, true, alwaysDirtyMask, unsafe));
}
for (MappingConstructorImpl<?> constructor : constructors) {
int constructorParameterCount = attributeFields.length + constructor.getParameterAttributes().size();
// Skip the empty constructor which was handled before
if (constructor.getParameterAttributes().size() == 0) {
continue;
}
CtClass[] constructorAttributeTypes = new CtClass[constructorParameterCount];
System.arraycopy(attributeTypes, 0, constructorAttributeTypes, 0, attributeFields.length);
// Append super constructor parameters to default constructor parameters
CtConstructor superConstructor = findConstructor(superCc, constructor);
System.arraycopy(superConstructor.getParameterTypes(), 0, constructorAttributeTypes, attributeFields.length, superConstructor.getParameterTypes().length);
cc.addConstructor(createNormalConstructor(entityViewManager, managedViewType, constructor, cc, attributeFields, constructorAttributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, alwaysDirtyMask, unsafe));
cc.addConstructor(createTupleConstructor(managedViewType, constructor, cc, attributeFields.length, constructorAttributeTypes.length, attributeFields, constructorAttributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, false, alwaysDirtyMask, unsafe));
cc.addConstructor(createTupleConstructor(managedViewType, constructor, cc, attributeFields.length, constructorAttributeTypes.length, attributeFields, constructorAttributeTypes, initialStateField, mutableStateField, methodAttributes, mutableAttributeCount, true, alwaysDirtyMask, unsafe));
}
return defineOrGetClass(entityViewManager, unsafe, clazz, clazz, cc);
} catch (Exception ex) {
throw new RuntimeException("Probably we did something wrong, please contact us if you see this message.", ex);
} finally {
pool.removeClassPath(classPath);
}
}
use of com.blazebit.persistence.view.impl.metamodel.MappingConstructorImpl in project blaze-persistence by Blazebit.
the class EntityViewSettingHelper method apply.
@SuppressWarnings("unchecked")
public static <T, Q extends FullQueryBuilder<T, Q>> Q apply(EntityViewSetting<T, Q> setting, EntityViewManagerImpl evm, CriteriaBuilder<?> criteriaBuilder, String entityViewRoot) {
ManagedViewTypeImplementor<?> managedView = evm.getMetamodel().managedView(setting.getEntityViewClass());
if (managedView == null) {
throw new IllegalArgumentException("There is no entity view for the class '" + setting.getEntityViewClass().getName() + "' registered!");
}
MappingConstructorImpl<?> mappingConstructor = (MappingConstructorImpl<?>) managedView.getConstructor(setting.getViewConstructorName());
if (managedView instanceof FlatViewType<?>) {
if (managedView.hasJoinFetchedCollections()) {
throw new IllegalArgumentException("Can't use the flat view '" + managedView.getJavaType().getName() + "' as view root because it contains join fetched collections! " + "Consider adding a @IdMapping to the entity view or use a different fetch strategy for the collections!");
}
if (mappingConstructor == null) {
if (managedView.getConstructors().size() > 1) {
mappingConstructor = (MappingConstructorImpl<T>) managedView.getConstructor("init");
} else if (managedView.getConstructors().size() == 1) {
mappingConstructor = (MappingConstructorImpl<T>) managedView.getConstructors().toArray()[0];
}
}
if (mappingConstructor != null && mappingConstructor.hasJoinFetchedCollections()) {
throw new IllegalArgumentException("Can't use the flat view '" + managedView.getJavaType().getName() + "' with the mapping constructor '" + mappingConstructor.getName() + "' as view root because it contains join fetched collections! " + "Consider adding a @IdMapping to the entity view or use a different fetch strategy for the collections!");
}
}
if (managedView.isUpdatable() && !setting.getFetches().isEmpty()) {
throw new IllegalArgumentException("Specifying fetches for @UpdatableEntityViews is currently disallowed. Remove the fetches!");
}
ExpressionFactory ef = criteriaBuilder.getService(ExpressionFactory.class);
Map<String, Object> optionalParameters;
if (setting.getOptionalParameters().isEmpty()) {
optionalParameters = evm.getOptionalParameters();
} else {
optionalParameters = new HashMap<>(evm.getOptionalParameters());
optionalParameters.putAll(setting.getOptionalParameters());
optionalParameters = Collections.unmodifiableMap(optionalParameters);
}
Collection<String> requestedFetches;
if (setting.getFetches().isEmpty() || !setting.hasAttributeFilters() && !setting.hasAttributeSorters()) {
requestedFetches = setting.getFetches();
} else {
requestedFetches = new HashSet<>(setting.getFetches());
addFetchesForNonMappingAttributes(setting.getAttributeFilterActivations().keySet(), managedView, requestedFetches);
addFetchesForNonMappingAttributes(setting.getAttributeSorters().keySet(), managedView, requestedFetches);
}
Path root = criteriaBuilder.getPath(entityViewRoot);
entityViewRoot = root.getPath();
Q queryBuilder = getQueryBuilder(setting, criteriaBuilder, entityViewRoot, managedView, setting.getProperties());
EntityViewConfiguration configuration = new EntityViewConfiguration(queryBuilder, ef, new MutableViewJpqlMacro(), new MutableEmbeddingViewJpqlMacro(), optionalParameters, setting.getProperties(), requestedFetches, managedView);
queryBuilder.selectNew(evm.createObjectBuilder(managedView, mappingConstructor, root.getJavaType(), entityViewRoot, null, criteriaBuilder, configuration, 0, 0, false));
Set<String> fetches = configuration.getFetches();
applyAttributeFilters(setting, evm, queryBuilder, entityViewRoot, fetches, managedView);
applyViewFilters(setting, evm, queryBuilder, managedView);
applyAttributeSorters(setting, queryBuilder, entityViewRoot, fetches, managedView);
applyOptionalParameters(optionalParameters, queryBuilder);
return queryBuilder;
}
Aggregations