blob: 1d780ec6074bc03227e95579b91fd7f826bc5230 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// dclarke, mnorman - Dynamic Persistence
// http://wiki.eclipse.org/EclipseLink/Development/Dynamic
// (https://bugs.eclipse.org/bugs/show_bug.cgi?id=200045)
//
package org.eclipse.persistence.internal.dynamic;
//javase imports
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
//EclipseLink imports
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.dynamic.DynamicType;
import org.eclipse.persistence.exceptions.DynamicException;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
/**
* An EntityType provides a metadata facade into the EclipseLink
* object-relational metadata (descriptors & mappings) with specific knowledge
* of the entity types being dynamic.
*
* @author dclarke, mnorman
* @since EclipseLink 1.2
*/
public class DynamicTypeImpl implements DynamicType, Cloneable {
protected ClassDescriptor descriptor;
protected DynamicType parentType;
protected DynamicPropertiesManager dpm;
/**
* These properties require initialization when a new instance is created.
* This includes properties that are primitives as well as relationships
* requiring indirection ValueHolders or collections.
*/
protected Set<DatabaseMapping> mappingsRequiringInitialization = new HashSet<>();
protected DynamicTypeImpl() {
super();
}
/**
* Creation of an EntityTypeImpl for an existing Descriptor with mappings.
*
*/
public DynamicTypeImpl(ClassDescriptor descriptor, DynamicType parentType) {
this();
this.descriptor = descriptor;
this.parentType = parentType;
}
@Override
public Object clone() {
// clone yerself
try {
return super.clone();
}
catch (Exception exception) {
throw new AssertionError(exception);
}
}
@Override
public ClassDescriptor getDescriptor() {
return this.descriptor;
}
public void setDescriptor(ClassDescriptor descriptor) {
this.descriptor = descriptor;
}
public DynamicPropertiesManager getDynamicPropertiesManager() {
return dpm;
}
public void setDynamicPropertiesManager(DynamicPropertiesManager dpm) {
this.dpm = dpm;
}
@Override
public DynamicType getParentType() {
return this.parentType;
}
public List<DatabaseMapping> getMappings() {
return getDescriptor().getMappings();
}
/**
* @see DynamicType#getName()
*/
@Override
public String getName() {
return getDescriptor().getAlias();
}
@Override
public String getClassName() {
return getDescriptor().getJavaClassName();
}
@Override
public int getNumberOfProperties() {
return dpm.getPropertyNames().size();
}
public Set<DatabaseMapping> getMappingsRequiringInitialization() {
return mappingsRequiringInitialization;
}
public boolean isInitialized() {
return getDescriptor().isFullyInitialized();
}
@Override
public boolean containsProperty(String propertyName) {
return dpm.contains(propertyName);
}
@Override
public Class<? extends DynamicEntity> getJavaClass() {
return getDescriptor().getJavaClass();
}
public DatabaseMapping getMapping(String propertyName) {
DatabaseMapping mapping = getDescriptor().getMappingForAttributeName(propertyName);
if (mapping == null) {
throw DynamicException.invalidPropertyName(this, propertyName);
}
return mapping;
}
@Override
public List<String> getPropertiesNames() {
return dpm.getPropertyNames();
}
@Override
public Class<?> getPropertyType(String propertyName) {
return getMapping(propertyName).getAttributeClassification();
}
@Override
public DynamicEntity newDynamicEntity() {
DynamicEntity newDynamicEntity = (DynamicEntity)getDescriptor().getInstantiationPolicy().
buildNewInstance();
return newDynamicEntity;
}
/**
* Ensure the value being set is supported by the mapping. If the mapping is
* direct/basic and the mapping's type is primitive ensure the non-primitive
* type is allowed.
*/
public void checkSet(String propertyName, Object value) throws DynamicException {
DatabaseMapping mapping = getMapping(propertyName);
if (value == null) {
if (mapping.isCollectionMapping() ||
(mapping.getAttributeClassification() != null &&
mapping.getAttributeClassification().isPrimitive())) {
throw DynamicException.invalidSetPropertyType(mapping, null);
}
return;
}
Class<?> expectedType = mapping.getAttributeClassification();
if (mapping.isForeignReferenceMapping()) {
if (mapping.isCollectionMapping()) {
if (mapping.getContainerPolicy().isMapPolicy()) {
expectedType = Map.class;
} else {
expectedType = Collection.class;
}
} else {
expectedType = ((ForeignReferenceMapping)mapping).getReferenceClass();
}
}
if (expectedType != null && expectedType.isPrimitive() && !value.getClass().isPrimitive()) {
expectedType = Helper.getObjectClass(expectedType);
}
if (expectedType != null && !expectedType.isAssignableFrom(value.getClass())) {
throw DynamicException.invalidSetPropertyType(mapping, value);
}
}
@Override
public int getPropertyIndex(String propertyName) {
return dpm.getPropertyNames().indexOf(propertyName);
}
@Override
public Class<?> getPropertyType(int propertyIndex) {
return getDescriptor().getMappings().get(propertyIndex).getAttributeClassification();
}
@Override
public String toString() {
return "DynamicEntityType(" + getName() + ") - " + getDescriptor();
}
}