Methods Summary |
---|
protected oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.ClassAccessor | buildAccessor(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor embeddableDescriptor)INTERNAL:
This method is responsible for configuring the right MetadataAccessor
object for processing of the Embeddable class represented by the
embeddableDescriptor that is passed in. This methood associates the
accessor with the descriptor as well.
ClassAccessor embeddableAccessor = null;
Class embeddableClass = embeddableDescriptor.getJavaClass();
if (m_project.hasEmbeddable(embeddableClass)) {
Node node = m_project.getEmbeddableNode(embeddableClass);
XMLHelper helper = m_project.getEmbeddableHelper(embeddableClass);
embeddableAccessor = new XMLClassAccessor(new MetadataClass(embeddableClass), node, helper, m_processor, embeddableDescriptor);
} else if (MetadataHelper.isAnnotationPresent(Embeddable.class, embeddableClass, embeddableDescriptor)) {
embeddableAccessor = new ClassAccessor(new MetadataClass(embeddableClass), m_processor, embeddableDescriptor);
} else {
m_validator.throwInvalidEmbeddedAttribute(getJavaClass(), m_accessibleObject.getName(), embeddableClass);
}
// associate the accessor to the descriptor (as per Javadoc)
embeddableDescriptor.setClassAccessor(embeddableAccessor);
return embeddableAccessor;
|
protected oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.EmbeddedAccessor$AccessType | computeAccessTypeFromAnnotation(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor descriptor)INTERNAL:
This method computes access-type based on placement of annotations.
Class javaClass = descriptor.getJavaClass();
boolean fieldAccess = MetadataHelper.havePersistenceAnnotationsDefined(MetadataHelper.getFields(javaClass));
boolean propertyAccess = MetadataHelper.havePersistenceAnnotationsDefined(MetadataHelper.getMethods(javaClass));
AccessType accessType = UNDEFINED;
if (fieldAccess && propertyAccess) {
accessType = MIXED;
} else if (fieldAccess) {
accessType = FIELD;
} else if (propertyAccess) {
accessType = PROPERTY;
}
return accessType;
|
protected oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.EmbeddedAccessor$AccessType | computeAccessTypeFromXML(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor descriptor)INTERNAL:
This method computes access-type based on metadata specified in mapping
XML file. If there is a default value for access is specified in
or and either there is
no for the given class or there is specified
in the , the default value is used.
// step #1: what's PU level default
String access = m_project.getPersistenceUnit() != null ? m_project.getPersistenceUnit().getAccess() : null;
// step #2: what's specified in <embeddable> element
Class javaClass = descriptor.getJavaClass();
if (m_project.hasEmbeddable(javaClass)) {
XMLHelper helper = m_project.getEmbeddableHelper(javaClass);
Node node = m_project.getEmbeddableNode(javaClass);
// override pu-level value by <embeddable> level if any
// Note, we pass the puLevel value as the default value
access = helper.getNodeValue(node, XMLConstants.ATT_ACCESS, access);
}
AccessType accessType = UNDEFINED;
if (access != null && access.length() != 0) {
accessType = AccessType.valueOf(access);
}
return accessType;
|
protected oracle.toplink.essentials.internal.ejb.cmp3.metadata.accessors.EmbeddedAccessor$AccessType | determineAccessTypeOfEmbedded(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor emDesc)INTERNAL:
This method is responsible for determining the access-type for an
Embeddable class represented by emDescr that is passed to
this method. This method should *not* be called more than once as this is
quite expensive. Now the rules:
Rule 1: In the *absence* of metadata in embeddable class, access-type of
an embeddable is determined by the access-type of the enclosing entity.
Rule 2: In the presence of metadata in embeddable class, access-type of
an embeddable is determined using that metadata. This allows sharing
of the embeddable in entities with conflicting access-types.
Rule 3: It is an error to use a *metadata-less* embeddable class in
entities with conflicting access-types as that might result in
different database mapping for the same embeddable class.
Rule 4: It is an error if metadata-complete == false, and
metadata is present *both* in annotations and XML, and
access-type as determined by each of them is *not* same.
Rule 5: It is an error if *both* fields and properties of an embeddable
class are annotated and metadata-complete == false.
final AccessType entityAccessType = m_descriptor.usesPropertyAccess() ? PROPERTY : FIELD;
AccessType accessType = UNDEFINED;
final boolean metadataComplete =emDesc.ignoreAnnotations();
final AccessType accessTypeUsingAnnotation = computeAccessTypeFromAnnotation(emDesc);
final AccessType accessTypeUsingXML = computeAccessTypeFromXML(emDesc);
if (metadataComplete) {
// metadata-complete is true, then use XML access-type if defined,
// else use enclosing entity's access-type.
accessType = accessTypeUsingXML != UNDEFINED ? accessTypeUsingXML : entityAccessType;
} else {// metadata-complete is false
if (accessTypeUsingAnnotation == UNDEFINED && accessTypeUsingAnnotation == UNDEFINED) {
// metadata is absent, so we use enclosing entity's access-type
accessType = entityAccessType;
} else if (accessTypeUsingXML == UNDEFINED && accessTypeUsingAnnotation != UNDEFINED) {
// annotation is present in embeddable class
accessType = accessTypeUsingAnnotation;
if (accessType == MIXED) {
m_validator.throwBothFieldsAndPropertiesAnnotatedException(emDesc.getJavaClass());
}
} else if (accessTypeUsingAnnotation == UNDEFINED && accessTypeUsingXML != UNDEFINED) {
// access is defined using XML for embeddable class
accessType = accessTypeUsingXML;
} else if (accessTypeUsingAnnotation == accessTypeUsingXML) {
// annotation is present as well as access is defined using XML
// and they are same. So use it.
accessType = accessTypeUsingAnnotation;
} else {
// annotation is present as well as access is defined using XML
// and they are different. So report an exception.
m_validator.throwIncorrectOverridingOfAccessType(emDesc.getJavaClass(), accessTypeUsingXML.toString(), accessTypeUsingAnnotation.toString());
}
}
// we have taken every precaution to make sure that either an embeddable
// has a well defined access-type or a suitable ValidationException
// is thrown.
assert(accessType != UNDEFINED && accessType != MIXED);
return accessType;
|
public boolean | isEmbedded()INTERNAL:
return true;
|
protected boolean | isMetadataComplete(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor emDesc)INTERNAL:
This method is used to decide if annotations should be ignored or not for
the given embeddable class.
final Class emClass = emDesc.getJavaClass();
boolean metadataComplete = m_project.getPersistenceUnit() != null ? m_project.getPersistenceUnit().isMetadataComplete() : false;
if (!metadataComplete) {
// check <embeddable>
if (m_project.hasEmbeddable(emClass)) {
XMLHelper helper = m_project.getEmbeddableHelper(emClass);
Node node = m_project.getEmbeddableNode(emClass);
// check if metadata-complete at <embeddable> level
metadataComplete = helper.getNodeValue(node, XMLConstants.ATT_METADATA_COMPLETE, false);
}
}
return metadataComplete;
|
protected boolean | isMetadataPresent(oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor descriptor)INTERNAL:
This method is used to decide if a class metadata or not.
AccessType annotAccessType = computeAccessTypeFromAnnotation(descriptor);
AccessType xmlAccessType = computeAccessTypeFromXML(descriptor);
return annotAccessType != UNDEFINED || xmlAccessType != UNDEFINED;
|
public void | process()INTERNAL: (Overridden in EmbeddedIdAccessor)
Process an @Embedded or embedded element.
// Tell the Embeddable class to process itself
MetadataDescriptor referenceDescriptor = processEmbeddableClass();
// Store this descriptor metadata. It may be needed again later on to
// look up a mappedBy attribute.
m_descriptor.addAggregateDescriptor(referenceDescriptor);
if (m_descriptor.hasMappingForAttributeName(getAttributeName())) {
// XML/Annotation merging. XML wins, ignore annotations.
m_logger.logWarningMessage(m_logger.IGNORE_MAPPING, m_descriptor, this);
} else {
// Create an aggregate mapping and do the rest of the work.
AggregateObjectMapping mapping = new AggregateObjectMapping();
mapping.setIsReadOnly(false);
mapping.setIsNullAllowed(true);
mapping.setReferenceClassName(getReferenceClassName());
mapping.setAttributeName(getAttributeName());
// Will check for PROPERTY access
setAccessorMethods(mapping);
// Process attribute overrides.
processAttributeOverrides(mapping);
// Process association overrides.
processAssociationOverrides(mapping);
// Add the mapping to the descriptor and we are done.
m_descriptor.addMapping(mapping);
}
|
protected void | processAssociationOverride(javax.persistence.AssociationOverride associationOverride, oracle.toplink.essentials.mappings.AggregateObjectMapping aggregateMapping)INTERNAL:
Process an @AssociationOverride for an embedded object, that is, an
aggregate object mapping in TopLink.
This functionality is not supported in XML, hence why this method is
defined here instead of on MetadataProcessor.
Also this functionality is currently optional in the EJB 3.0 spec, but
since TopLink can handle it, it is implemented and assumes the user has
properly configured its use since it will fail silently.
MetadataDescriptor aggregateDescriptor = getReferenceDescriptor();
// AssociationOverride.name(), the name of the attribute we want to
// override.
String name = associationOverride.name();
DatabaseMapping mapping = aggregateDescriptor.getMappingForAttributeName(name);
if (mapping != null && mapping.isOneToOneMapping()) {
int index = 0;
for (JoinColumn joinColumn : associationOverride.joinColumns()) {
// We can't change the mapping from the aggregate descriptor
// so we have to add field name translations. This needs to be
// tested since I am not entirely sure if this will acutally
// work.
// In composite primary key case, how do we association the
// foreign keys? Right now we assume the association overrides
// are specified in the same order as the original joinColumns,
// therefore in the same order the foreign keys were added to
// the mapping.
DatabaseField fkField = (DatabaseField) ((OneToOneMapping) mapping).getForeignKeyFields().elementAt(index++);
aggregateMapping.addFieldNameTranslation(joinColumn.name(), fkField.getName());
}
} else {
// For now fail silently.
}
|
protected void | processAssociationOverrides(oracle.toplink.essentials.mappings.AggregateObjectMapping mapping)INTERNAL:
Process an @AssociationOverrides for an embedded object, that is, an
aggregate object mapping in TopLink.
It will also look for an @AssociationOverride.
// Look for an @AssociationOverrides.
AssociationOverrides associationOverrides = getAnnotation(AssociationOverrides.class);
if (associationOverrides != null) {
for (AssociationOverride associationOverride : associationOverrides.value()) {
processAssociationOverride(associationOverride, mapping);
}
}
// Look for an @AssociationOverride.
AssociationOverride associationOverride = getAnnotation(AssociationOverride.class);
if (associationOverride != null) {
processAssociationOverride(associationOverride, mapping);
}
|
protected void | processAttributeOverride(oracle.toplink.essentials.mappings.AggregateObjectMapping mapping, oracle.toplink.essentials.internal.ejb.cmp3.metadata.columns.MetadataColumn column)INTERNAL: (Overridden in EmbeddedIdAccessor)
Process an @AttributeOverride or attribute-override element for an
embedded object, that is, an aggregate object mapping in TopLink.
String attributeName = column.getAttributeName();
// Set the attribute name on the aggregate.
DatabaseMapping aggregateMapping = getReferenceDescriptor().getMappingForAttributeName(attributeName);
if (aggregateMapping == null) {
m_validator.throwInvalidEmbeddableAttribute(getJavaClass(), mapping.getAttributeName(), getReferenceDescriptor().getJavaClass(), attributeName);
}
// A sub-class to a mapped superclass may override an embedded attribute
// override.
if (m_descriptor.hasAttributeOverrideFor(attributeName)) {
// Update the field on this metadata column. We do that so that
// an embedded id can associate the correct id fields.
column.setDatabaseField(m_descriptor.getAttributeOverrideFor(attributeName).getDatabaseField());
}
mapping.addFieldNameTranslation(column.getDatabaseField().getQualifiedName(), aggregateMapping.getField().getName());
|
protected void | processAttributeOverrides(oracle.toplink.essentials.mappings.AggregateObjectMapping mapping)INTERNAL: (Overridden in XMLEmbeddedAccessor and XMLEmbeddedIdAccessor)
Process an @AttributeOverrides for an embedded object, that is, an
aggregate object mapping in TopLink.
It will also look for an @AttributeOverride.
// Look for an @AttributeOverrides.
AttributeOverrides attributeOverrides = getAnnotation(AttributeOverrides.class);
if (attributeOverrides != null) {
for (AttributeOverride attributeOverride : attributeOverrides.value()) {
processAttributeOverride(mapping, new MetadataColumn(attributeOverride.column(), attributeOverride.name(), getAnnotatedElement()));
}
}
// Look for an @AttributeOverride.
AttributeOverride attributeOverride = getAnnotation(AttributeOverride.class);
if (attributeOverride != null) {
processAttributeOverride(mapping, new MetadataColumn(attributeOverride.column(), attributeOverride.name(), getAnnotatedElement()));
}
|
protected oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataDescriptor | processEmbeddableClass()INTERNAL: (Overridden in EmbeddedIdAccessor)
This method processes an embeddable class, if we have not processed it
yet. The reason for lazy processing of embeddable class is because of
rules governing access-type of embeddable. See GlassFish issue #831 for
more details.
Be careful while changing order of processing.
final Class embeddableClass = getReferenceClass();
MetadataDescriptor embeddableDescriptor = null;
try {
embeddableDescriptor = m_project.getDescriptor(embeddableClass);
} catch (Exception exception) {
// expected as we do lazy processing of embeddables.
}
if (embeddableDescriptor == null) {
// The embeddable class is not yet processed, so process it now.
embeddableDescriptor = new MetadataDescriptor(embeddableClass);
// adding to projects sets up appropriate persistence-unit-defaults
m_project.addDescriptor(embeddableDescriptor);
embeddableDescriptor.setIgnoreAnnotations(isMetadataComplete(embeddableDescriptor));
AccessType accessType = determineAccessTypeOfEmbedded(embeddableDescriptor);
embeddableDescriptor.setUsesPropertyAccess(accessType == PROPERTY ? true : false);
ClassAccessor embeddableAccessor = buildAccessor(embeddableDescriptor);
embeddableAccessor.process();
embeddableAccessor.setIsProcessed();
} else {
// We have already processed this embeddable class. let's validate
// that it is not used in entities with conflicting access type.
// Conflicting access-type is not allowed when there is no metadata
// in the embeddable class.
if (!isMetadataPresent(embeddableDescriptor)) {
boolean embeddableUsesPropertyAccess = embeddableDescriptor.usesPropertyAccess();
boolean entityUsesPropertyAccess = m_descriptor.usesPropertyAccess();
if (embeddableUsesPropertyAccess != entityUsesPropertyAccess) {
m_validator.throwConflictingAccessTypeInEmbeddable(embeddableClass);
}
}
}
return embeddableDescriptor;
|