
org.fastnate.generator.context.PluralProperty Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastnate-generator Show documentation
Show all versions of fastnate-generator Show documentation
The Fastnate Offline SQL Generator
package org.fastnate.generator.context;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.Access;
import javax.persistence.AssociationOverride;
import javax.persistence.AttributeOverride;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MapsId;
import org.fastnate.generator.statements.InsertStatement;
import lombok.Getter;
/**
* Base class for {@link MapProperty} and {@link CollectionProperty}.
*
* @author Tobias Liefke
* @param
* The type of the container class
* @param
* The type of the collection of map
* @param
* The type of the elements in the collection
*/
@Getter
public abstract class PluralProperty extends Property {
/**
* Builds the name of the column that contains the ID of the entity for the given attribute.
*
* @param attribute
* the accessor for the inspected attribute
* @param override
* contains optional override options
* @param collectionMetadata
* the default join column
* @param defaultIdColumn
* the default name for the column, if {@code joinColumn} is empty or {@code null}
* @return the column name
*/
protected static String buildIdColumn(final AttributeAccessor attribute, final AssociationOverride override,
final CollectionTable collectionMetadata, final String defaultIdColumn) {
return buildIdColumn(attribute, override, collectionMetadata != null ? collectionMetadata.joinColumns() : null,
defaultIdColumn);
}
/**
* Builds the name of the column that contains the ID of the entity for the given attribute.
*
* @param attribute
* the inspected attribute
* @param override
* contains optional override options
* @param joinColumns
* the default join columns
* @param defaultIdColumn
* the default name for the column, if {@code joinColumn} is empty or {@code null}
* @return the column name
*/
private static String buildIdColumn(final AttributeAccessor attribute, final AssociationOverride override,
final JoinColumn[] joinColumns, final String defaultIdColumn) {
if (override != null && override.joinColumns().length > 0) {
final JoinColumn joinColumn = override.joinColumns()[0];
if (joinColumn.name().length() > 0) {
return joinColumn.name();
}
}
final JoinColumn joinColumn = attribute.getAnnotation(JoinColumn.class);
if (joinColumn != null && joinColumn.name().length() > 0) {
return joinColumn.name();
}
if (joinColumns != null && joinColumns.length > 0 && joinColumns[0].name().length() > 0) {
return joinColumns[0].name();
}
return defaultIdColumn;
}
/**
* Builds the name of the column that contains the ID of the entity for the given attribute.
*
* @param attribute
* the inspected attribute
* @param override
* contains optional override options
* @param joinTable
* the optional join table date
* @param tableMetadata
* the optional
* @param defaultIdColumn
* the default name for the column, if {@code joinColumn} is empty or {@code null}
* @return the column name
*/
protected static String buildIdColumn(final AttributeAccessor attribute, final AssociationOverride override,
final JoinTable joinTable, final CollectionTable tableMetadata, final String defaultIdColumn) {
return buildIdColumn(attribute, override, joinTable != null ? joinTable.joinColumns()
: tableMetadata != null ? tableMetadata.joinColumns() : null, defaultIdColumn);
}
/**
* Builds the name of the table of the association for the given field.
*
* @param attribute
* the inspected field
* @param override
* contains optional override options
* @param joinTable
* the optional join table
* @param collectionTable
* the optional metadata of the table
* @param defaultTableName
* the default name for the table
* @return the table name
*/
protected static String buildTableName(final AttributeAccessor attribute, final AssociationOverride override,
final JoinTable joinTable, final CollectionTable collectionTable, final String defaultTableName) {
if (override != null) {
final JoinTable joinTableOverride = override.joinTable();
if (joinTableOverride != null && joinTableOverride.name().length() > 0) {
return joinTableOverride.name();
}
}
if (joinTable != null && joinTable.name().length() > 0) {
return joinTable.name();
}
if (collectionTable != null && collectionTable.name().length() > 0) {
return collectionTable.name();
}
return defaultTableName;
}
/**
* Builds the name of the table of the association for the given field.
*
* @param tableMetadata
* the current metadata of the field
* @param defaultTableName
* the default name for the table
* @return the column name
*/
protected static String buildTableName(final CollectionTable tableMetadata, final String defaultTableName) {
return tableMetadata != null && tableMetadata.name().length() != 0 ? tableMetadata.name() : defaultTableName;
}
/**
* Builds the name of the column that contains the value for the collection / map.
*
* @param attribute
* the inspected attribute
* @param defaultValueColumn
* the default name
* @return the column name
*/
protected static String buildValueColumn(final AttributeAccessor attribute, final String defaultValueColumn) {
final JoinTable tableMetadata = attribute.getAnnotation(JoinTable.class);
if (tableMetadata != null && tableMetadata.inverseJoinColumns().length > 0
&& tableMetadata.inverseJoinColumns()[0].name().length() > 0) {
return tableMetadata.inverseJoinColumns()[0].name();
}
final Column columnMetadata = attribute.getAnnotation(Column.class);
if (columnMetadata != null && columnMetadata.name().length() > 0) {
return columnMetadata.name();
}
return defaultValueColumn;
}
/**
* Inspects the given attribute and searches for a generic type argument.
*
* @param attribute
* the attribute to inspect
* @param explicitClass
* an explicit class to use, if the metadata specified one
* @param argumentIndex
* the index of the argument, for maps there are two: the key and the value
* @return the found class
*/
@SuppressWarnings("unchecked")
protected static Class getPropertyArgument(final AttributeAccessor attribute, final Class explicitClass,
final int argumentIndex) {
if (explicitClass != void.class) {
// Explict target class
return explicitClass;
}
// Inspect the type binding
if (!(attribute.getGenericType() instanceof ParameterizedType)) {
throw new ModelException(attribute + " is not of generic type and has no defined entity class");
}
final ParameterizedType type = (ParameterizedType) attribute.getGenericType();
final Type[] parameterArgTypes = type.getActualTypeArguments();
if (parameterArgTypes.length > argumentIndex) {
Type genericType = parameterArgTypes[argumentIndex];
if (genericType instanceof ParameterizedType) {
genericType = ((ParameterizedType) genericType).getRawType();
}
if (genericType instanceof Class>) {
return (Class) genericType;
}
}
throw new ModelException(attribute + " has illegal generic type signature");
}
/** The current context. */
private final GeneratorContext context;
/** Contains all properties of an embedded element collection. */
private List> embeddedProperties;
/** The property to use, if an id is embedded. */
private final String mappedId;
/**
* Creates a new property.
*
* @param context
* the current context
* @param attribute
* accessor to the represented attribute
*/
public PluralProperty(final GeneratorContext context, final AttributeAccessor attribute) {
super(attribute);
this.context = context;
final MapsId mapsId = attribute.getAnnotation(MapsId.class);
this.mappedId = mapsId == null || mapsId.value().length() == 0 ? null : mapsId.value();
}
@Override
public void addInsertExpression(final E entity, final InsertStatement statement) {
// Ignore
}
/**
* Builds the embedded properties of this property.
*
* @param targetType
* the target type
*/
protected void buildEmbeddedProperties(final Class> targetType) {
if (targetType.isAnnotationPresent(Embeddable.class)) {
// Determine the access style
final AccessStyle accessStyle;
final Access accessType = targetType.getAnnotation(Access.class);
if (accessType != null) {
accessStyle = AccessStyle.getStyle(accessType.value());
} else {
accessStyle = getAttribute().getAccessStyle();
}
this.embeddedProperties = new ArrayList<>();
final Map attributeOverrides = EntityClass
.getAttributeOverrides(getAttribute().getElement());
final Map accociationOverrides = EntityClass
.getAccociationOverrides(getAttribute().getElement());
for (final AttributeAccessor attribute : accessStyle.getDeclaredAttributes(targetType)) {
final AttributeOverride attributeOveride = attributeOverrides.get(attribute.getName());
final Column columnMetadata = attributeOveride != null ? attributeOveride.column()
: attribute.getAnnotation(Column.class);
final AssociationOverride assocOverride = accociationOverrides.get(attribute.getName());
final SingularProperty property = buildProperty(attribute, columnMetadata, assocOverride);
if (property != null) {
this.embeddedProperties.add(property);
}
}
}
}
private SingularProperty buildProperty(final AttributeAccessor attribute, final Column columnMetadata,
final AssociationOverride override) {
// Ignore static, transient and generated fields
if (attribute.isPersistent()) {
if (CollectionProperty.isCollectionProperty(attribute) || MapProperty.isMapProperty(attribute)) {
throw new ModelException("Plural attributes not allowed for embedded element collection: " + attribute);
}
if (EntityProperty.isEntityProperty(attribute)) {
return new EntityProperty<>(this.context, attribute, override);
}
return new PrimitiveProperty<>(this.context, getTable(), attribute, columnMetadata);
}
return null;
}
/**
* The name of the column that contains the ID of the entity that contains this collection.
*
* @return the name of the ID column
*/
public abstract String getIdColumn();
/**
* The name of the table of this property, if any.
*
* @return the name of the table
*/
public abstract String getTable();
/**
* The name of the column that contains the values of the collection.
*
* @return the name of the value column or {@code null} if {@link #isEmbedded() embedded}
*/
public abstract String getValueColumn();
/**
* Indicates that this propery is a {@link ElementCollection} that references {@link Embeddable}s.
*
* @return true if {@code getEmbeddedProperties()} returns a list of properties
*/
public boolean isEmbedded() {
return this.embeddedProperties != null;
}
@Override
public boolean isRequired() {
return false;
}
@Override
public boolean isTableColumn() {
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy