com.caucho.amber.cfg.OneToManyConfig Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Rodrigo Westrupp
*/
package com.caucho.amber.cfg;
import com.caucho.amber.field.AmberField;
import com.caucho.amber.field.ManyToManyField;
import com.caucho.amber.field.ManyToOneField;
import com.caucho.amber.field.OneToManyField;
import com.caucho.amber.manager.AmberPersistenceUnit;
import com.caucho.amber.table.AmberTable;
import com.caucho.amber.table.ForeignColumn;
import com.caucho.amber.table.LinkColumns;
import com.caucho.amber.type.EntityType;
import com.caucho.bytecode.JType;
import com.caucho.bytecode.JTypeWrapper;
import com.caucho.util.L10N;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
/**
* tag in orm.xml
*/
class OneToManyConfig extends AbstractRelationConfig
{
private static final L10N L = new L10N(OneToManyConfig.class);
private BaseConfigIntrospector _introspector;
private EntityType _sourceType;
private AccessibleObject _field;
private String _fieldName;
private Class _fieldType;
// attributes
private String _mappedBy;
// elements
private MapKeyConfig _mapKey;
private String _orderBy;
private HashMap _joinColumnMap
= new HashMap();
private ArrayList _orderByFields = null;
private ArrayList _orderByAscending = null;
OneToManyConfig(BaseConfigIntrospector introspector,
EntityType sourceType,
AccessibleObject field,
String fieldName,
Class fieldType)
{
_introspector = introspector;
_sourceType = sourceType;
_field = field;
_fieldName = fieldName;
_fieldType = fieldType;
setName(fieldName);
introspect();
}
public String getMappedBy()
{
return _mappedBy;
}
public void setMappedBy(String mappedBy)
{
_mappedBy = mappedBy;
}
public MapKeyConfig getMapKey()
{
return _mapKey;
}
public void setMapKey(MapKeyConfig mapKey)
{
_mapKey = mapKey;
}
public String getOrderBy()
{
return _orderBy;
}
public void setOrderBy(String orderBy)
{
_orderBy = orderBy;
}
public boolean isOwningSide()
{
return "".equals(_mappedBy);
}
private void introspect()
{
introspectTypes();
OneToMany oneToMany = _field.getAnnotation(OneToMany.class);
if (oneToMany != null)
introspectOneToMany(oneToMany);
JoinTable joinTableAnn = _field.getAnnotation(JoinTable.class);
if (joinTableAnn != null)
setJoinTable(new JoinTableConfig(joinTableAnn));
JoinColumn joinColumnAnn = _field.getAnnotation(JoinColumn.class);
JoinColumns joinColumnsAnn = _field.getAnnotation(JoinColumns.class);
if (joinColumnsAnn != null && joinColumnAnn != null) {
throw error(_field, L.l("{0} may not have both @JoinColumn and @JoinColumns",
_fieldName));
}
if (joinColumnsAnn != null)
introspectJoinColumns(joinColumnsAnn.value());
else if (joinColumnAnn != null)
introspectJoinColumns(new JoinColumn[] { joinColumnAnn });
OrderBy orderByAnn = _field.getAnnotation(OrderBy.class);
if (orderByAnn != null)
_orderBy = orderByAnn.value();
}
private void introspectTypes()
{
Type retType;
if (_field instanceof Field)
retType = ((Field) _field).getGenericType();
else
retType = ((Method) _field).getGenericReturnType();
ClassLoader loader = _sourceType.getPersistenceUnit().getTempClassLoader();
JType type = JTypeWrapper.create(retType, loader);
JType []typeArgs = type.getActualTypeArguments();
if (typeArgs.length > 0)
setTargetEntity(typeArgs[0].getRawType().getJavaClass());
}
private void introspectOneToMany(OneToMany oneToMany)
{
Class targetClass = oneToMany.targetEntity();
if (! void.class.equals(targetClass))
setTargetEntity(targetClass);
setCascadeTypes(oneToMany.cascade());
setFetch(oneToMany.fetch());
_mappedBy = oneToMany.mappedBy();
}
private void introspectJoinColumns(JoinColumn []joinColumns)
{
for (JoinColumn joinColumn : joinColumns) {
addJoinColumn(new JoinColumnConfig(joinColumn));
}
}
private void calculateOrderBy(String orderBy)
{
_orderByFields = new ArrayList();
_orderByAscending = new ArrayList();
int len = orderBy.length();
int i = 0;
while (i < len) {
int index = orderBy.indexOf(",", i);
if (index < 0)
index = len;
String orderByField = orderBy.substring(i, index);
i += index;
// ASC or DESC
index = orderByField.toUpperCase(Locale.ENGLISH).lastIndexOf("SC");
Boolean asc = Boolean.TRUE;
if (index > 1) {
if (orderByField.charAt(index - 1) != 'E') {
// field ASC or default
if (orderByField.charAt(index - 1) == 'A' &&
Character.isSpaceChar(orderByField.charAt(index - 2))) {
index -= 2;
}
}
else if (index > 2 &&
orderByField.charAt(index - 2) == 'D' &&
Character.isSpaceChar(orderByField.charAt(index - 3))) {
asc = Boolean.FALSE;
index -= 3;
}
}
if (index > 0)
orderByField = orderByField.substring(0, index).trim();
_orderByFields.add(orderByField);
_orderByAscending.add(asc);
}
}
public JoinColumnConfig getJoinColumn(String name)
{
return _joinColumnMap.get(name);
}
public void addJoinColumn(JoinColumnConfig joinColumn)
{
_joinColumnMap.put(joinColumn.getName(),
joinColumn);
}
public HashMap getJoinColumnMap()
{
return _joinColumnMap;
}
@Override
public EntityType getRelatedType()
{
return _sourceType;
}
@Override
public void complete()
{
AmberPersistenceUnit persistenceUnit = _sourceType.getPersistenceUnit();
Class targetEntity = getTargetEntity();
if (targetEntity == null)
throw error(_field, L.l("Can't determine targetEntity for {0}. @OneToMany properties must target @Entity beans.",
_fieldName));
EntityType targetType = persistenceUnit.getEntityType(targetEntity);
if (targetType == null) {
throw error(_field,
L.l("targetEntity '{0}' is not an @Entity bean for {1}. The targetEntity of a @OneToMany collection must be an @Entity bean.",
targetEntity.getName(),
_fieldName));
}
if (_orderBy != null)
calculateOrderBy(_orderBy);
if (! isOwningSide()) {
oneToManyBidirectional(targetType);
}
else {
oneToManyUnidirectional(targetType);
}
}
private void oneToManyBidirectional(EntityType targetType)
{
JoinTableConfig joinTableConfig = getJoinTable();
if (joinTableConfig != null) {
throw error(_field,
L.l("Bidirectional @ManyToOne property {0} may not have a @JoinTable annotation.",
_fieldName));
}
String mappedBy = getMappedBy();
ManyToOneField sourceField = getSourceField(targetType,
mappedBy,
null);
if (sourceField == null)
throw error(_field, L.l("'{1}' is an unknown column in '{0}' for @ManyToOne(mappedBy={1}).",
targetType.getName(),
mappedBy));
OneToManyField oneToMany;
oneToMany = new OneToManyField(_sourceType, _fieldName, getCascade());
oneToMany.setSourceField(sourceField);
oneToMany.setOrderBy(_orderByFields, _orderByAscending);
oneToMany.setLazy(isFetchLazy());
/*
if (! _annotationCfg.isNull()) {
String key = mapKeyAnn.name();
String getter = "get" +
Character.toUpperCase(key.charAt(0)) + key.substring(1);
Method method = targetType.getGetter(getter);
if (method == null) {
throw error(_field,
L.l("targetEntity '{0}' has no getter for field named '{1}'. Either the @MapKey name or the @OneToMany targetEntity is incorrect.",
targetName, key));
}
oneToMany.setMapKey(key);
}
*/
_sourceType.addField(oneToMany);
}
private void oneToManyUnidirectional(EntityType targetType)
{
ManyToManyField manyToManyField;
manyToManyField = new ManyToManyField(_sourceType, _fieldName,
getCascade());
manyToManyField.setType(targetType);
String sqlTable = _sourceType.getTable().getName() + "_" + targetType.getTable().getName();
JoinTable joinTableAnn = _field.getAnnotation(javax.persistence.JoinTable.class);
JoinTableConfig joinTableConfig = getJoinTable();
AmberTable mapTable = null;
ArrayList sourceColumns = null;
ArrayList targetColumns = null;
AmberPersistenceUnit persistenceUnit = _sourceType.getPersistenceUnit();
if (joinTableConfig != null) {
HashMap joinColumnsConfig = null;
HashMap inverseJoinColumnsConfig = null;
if (! joinTableConfig.getName().equals(""))
sqlTable = joinTableConfig.getName();
joinColumnsConfig = joinTableConfig.getJoinColumnMap();
inverseJoinColumnsConfig = joinTableConfig.getInverseJoinColumnMap();
mapTable = persistenceUnit.createTable(sqlTable);
sourceColumns
= calculateColumns(_field, _fieldName, mapTable,
_sourceType.getTable().getName() + "_",
_sourceType,
joinColumnsConfig);
targetColumns = calculateColumns(_field, _fieldName, mapTable,
targetType.getTable().getName() + "_",
targetType,
inverseJoinColumnsConfig);
}
else {
mapTable = persistenceUnit.createTable(sqlTable);
sourceColumns = calculateColumns(mapTable,
_sourceType.getTable().getName() + "_",
_sourceType);
targetColumns
= calculateColumns(mapTable,
// jpa/0j40
toSqlName(_fieldName) + "_",
targetType);
}
manyToManyField.setAssociationTable(mapTable);
manyToManyField.setTable(sqlTable);
manyToManyField.setSourceLink(new LinkColumns(mapTable,
_sourceType.getTable(),
sourceColumns));
manyToManyField.setTargetLink(new LinkColumns(mapTable,
targetType.getTable(),
targetColumns));
/*
if (mapKey != null) {
String key;
if (mapKeyAnn != null)
key = mapKeyAnn.name();
else
key = mapKeyConfig.getName();
String getter = "get" +
Character.toUpperCase(key.charAt(0)) + key.substring(1);
Method method = targetType.getGetter(getter);
if (method == null) {
throw error(_field,
L.l("targetEntity '{0}' has no getter for field named '{1}'. Either the @MapKey name or the @ManyToMany targetEntity is incorrect.",
targetName, key));
}
manyToManyField.setMapKey(key);
}
*/
_sourceType.addField(manyToManyField);
}
ManyToOneField getSourceField(EntityType targetType,
String mappedBy,
EntityType sourceType)
{
do {
ArrayList fields = targetType.getFields();
for (AmberField field : fields) {
// jpa/0o07: there is no mappedBy at all on any sides.
if ("".equals(mappedBy) || mappedBy == null) {
if (field.getJavaType().isAssignableFrom(sourceType.getBeanClass()))
return (ManyToOneField) field;
}
else if (field.getName().equals(mappedBy))
return (ManyToOneField) field;
}
// jpa/0ge4
targetType = targetType.getParentType();
}
while (targetType != null);
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy