com.caucho.amber.cfg.AbstractConfigIntrospector 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.IdField;
import com.caucho.amber.table.ForeignColumn;
import com.caucho.amber.type.AmberBeanType;
import com.caucho.amber.type.EntityType;
import com.caucho.config.ConfigException;
import com.caucho.util.L10N;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.logging.Logger;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import javax.persistence.JoinColumn;
import javax.persistence.Version;
/**
* Abstract introspector for orm.xml and annotations.
*/
abstract public class AbstractConfigIntrospector {
private static final Logger log
= Logger.getLogger(AbstractConfigIntrospector.class.getName());
private static final L10N L = new L10N(AbstractConfigIntrospector.class);
// annotations allowed for a property
static HashSet _propertyAnnotations
= new HashSet();
// types allowed with a @Basic annotation
static HashSet _basicTypes = new HashSet();
// annotations allowed with a @Basic annotation
static HashSet _basicAnnotations = new HashSet();
// types allowed with an @Id annotation
static HashSet _idTypes = new HashSet();
// annotations allowed with an @Id annotation
static HashSet _idAnnotations = new HashSet();
// annotations allowed with a @ManyToOne annotation
static HashSet _manyToOneAnnotations = new HashSet();
// annotations allowed with a @OneToMany annotation
static HashSet _oneToManyAnnotations = new HashSet();
// types allowed with a @OneToMany annotation
static HashSet _oneToManyTypes = new HashSet();
// annotations allowed with a @ManyToMany annotation
static HashSet _manyToManyAnnotations = new HashSet();
// types allowed with a @ManyToMany annotation
static HashSet _manyToManyTypes = new HashSet();
// annotations allowed with a @OneToOne annotation
static HashSet _oneToOneAnnotations = new HashSet();
// annotations allowed with a @ElementCollection annotation
static HashSet _elementCollectionAnnotations = new HashSet();
// types allowed with a @ElementCollection annotation
static HashSet _elementCollectionTypes = new HashSet();
// annotations allowed with a @Embedded annotation
static HashSet _embeddedAnnotations = new HashSet();
// annotations allowed with a @EmbeddedId annotation
static HashSet _embeddedIdAnnotations = new HashSet();
// annotations allowed with a @Version annotation
static HashSet _versionAnnotations = new HashSet();
// types allowed with an @Version annotation
static HashSet _versionTypes = new HashSet();
AnnotationConfig _annotationCfg = new AnnotationConfig();
/**
* Validates a callback method
*/
void validateCallback(String callbackName,
Method method,
boolean isListener)
throws ConfigException
{
if (Modifier.isFinal(method.getModifiers()))
throw error(method, L.l("'{0}' must not be final. @{1} methods may not be final.",
getFullName(method),
callbackName));
if (Modifier.isStatic(method.getModifiers()))
throw error(method, L.l("'{0}' must not be static. @{1} methods may not be static.",
getFullName(method),
callbackName));
Class params[] = method.getParameterTypes();
if (isListener) {
if (params.length != 1) {
throw error(method, L.l("'{0}' must have the (Object) signature for entity listeners.",
getFullName(method)));
}
}
else if (params.length != 0) {
throw error(method, L.l("'{0}' must not have any arguments. @{1} methods have zero arguments for entities or mapped superclasses.",
getFullName(method),
callbackName));
}
}
/**
* Validates the bean
*/
public void validateType(Class type, boolean isEntity)
throws ConfigException
{
if (Modifier.isFinal(type.getModifiers()))
throw new ConfigException(L.l("'{0}' must not be final. Entity beans may not be final.",
type.getName()));
// NOTE: Both abstract and concrete classes can be entities.
// MappedSuperclass does not need constructor validation.
if (isEntity)
validateConstructor(type);
for (Method method : type.getMethods()) {
if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
}
else if (Modifier.isFinal(method.getModifiers()))
throw error(method, L.l("'{0}' must not be final. Entity beans methods may not be final.",
getFullName(method)));
}
}
/**
* Checks for a valid constructor.
*/
public void validateConstructor(Class type)
throws ConfigException
{
for (Constructor ctor : type.getDeclaredConstructors()) {
Class []param = ctor.getParameterTypes();
if (param.length == 0
&& (Modifier.isPublic(ctor.getModifiers())
|| Modifier.isProtected(ctor.getModifiers())))
return;
}
// jpa/0gb2
throw new ConfigException(L.l("'{0}' needs a public or protected no-arg constructor. Entity beans must have a public or protected no-arg constructor.",
type.getName()));
}
/**
* Validates a non-getter method.
*/
public void validateNonGetter(Method method)
throws ConfigException
{
Annotation ann = isAnnotatedMethod(method);
if (ann != null && ! (ann instanceof Version)) {
throw error(method,
L.l("'{0}' is not a valid annotation for {1}. Only public getters and fields may have property annotations.",
ann, getFullName(method)));
}
}
/**
* Validates a non-getter method.
*/
Annotation isAnnotatedMethod(Method method)
throws ConfigException
{
for (Annotation ann : method.getDeclaredAnnotations()) {
if (_propertyAnnotations.contains(ann.getClass().getName())) {
return ann;
}
}
return null;
}
static boolean containsFieldOrCompletion(AmberBeanType type,
String fieldName)
{
// jpa/0l03
while (type != null) {
if (type.getField(fieldName) != null)
return true;
if (type.containsCompletionField(fieldName))
return true;
if (type instanceof EntityType)
type = ((EntityType) type).getParentType();
}
return false;
}
static void validateAnnotations(AccessibleObject field,
String fieldName,
String fieldType,
HashSet validAnnotations)
throws ConfigException
{
for (Annotation ann : field.getDeclaredAnnotations()) {
String name = ann.getClass().getName();
if (! name.startsWith("javax.persistence"))
continue;
if (! validAnnotations.contains(name)) {
throw error(field, L.l("{0} may not have a @{1} annotation. {2} does not allow @{3}.",
fieldName,
name,
fieldType,
name));
}
}
}
static String getFullName(Method method)
{
return method.getName();
}
static String toFieldName(String name)
{
// jpa/0g0d
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
/*
if (Character.isLowerCase(name.charAt(0)))
return name;
else if (name.length() == 1
|| ! Character.isUpperCase(name.charAt(1)))
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
else
return name;
*/
}
static ArrayList calculateColumns(com.caucho.amber.table.AmberTable mapTable,
EntityType type,
JoinColumn []joinColumns)
{
if (joinColumns == null || joinColumns.length == 0)
return calculateColumns(mapTable, type);
ArrayList columns = new ArrayList();
for (int i = 0; i < joinColumns.length; i++) {
ForeignColumn foreignColumn;
JoinColumn joinColumn = joinColumns[i];
foreignColumn =
mapTable.createForeignColumn(joinColumn.name(),
type.getId().getKey().getColumns().get(0));
columns.add(foreignColumn);
}
return columns;
}
static ArrayList
calculateColumns(AccessibleObject field,
String fieldName,
com.caucho.amber.table.AmberTable mapTable,
String prefix,
EntityType type,
JoinColumn []joinColumnsAnn,
HashMap joinColumnsConfig)
throws ConfigException
{
if ((joinColumnsAnn == null || joinColumnsAnn.length == 0) &&
(joinColumnsConfig == null || joinColumnsConfig.size() == 0))
return calculateColumns(mapTable, prefix, type);
ArrayList columns = new ArrayList();
// #1448 not reproduced.
if (type.getId() == null)
throw error(field, L.l("Entity {0} has no primary key defined.",
type.getName()));
ArrayList idFields = type.getId().getKeys();
int len;
if (joinColumnsAnn != null)
len = joinColumnsAnn.length;
else
len = joinColumnsConfig.size();
if (len != idFields.size()) {
throw error(field, L.l("@JoinColumns for {0} do not match number of the primary key columns in {1}. The foreign key columns must match the primary key columns.",
fieldName,
type.getName()));
}
Iterator it = null;
if (joinColumnsConfig != null)
it = joinColumnsConfig.values().iterator();
for (int i = 0; i < len; i++) {
ForeignColumn foreignColumn;
String name;
if (joinColumnsAnn != null) {
name = joinColumnsAnn[i].name();
}
else {
JoinColumnConfig joinColumnConfig = (JoinColumnConfig) it.next();
name = joinColumnConfig.getName();
}
foreignColumn =
mapTable.createForeignColumn(name,
idFields.get(i).getColumns().get(0));
columns.add(foreignColumn);
}
return columns;
}
static ConfigException error(AccessibleObject field, String msg)
{
if (field instanceof Field)
return error((Field) field, msg);
else
return error((Method) field, msg);
}
static ConfigException error(Field field, String msg)
{
// XXX: the field is for line numbers in the source, theoretically
String className = field.getDeclaringClass().getName();
int line = 0; //field.getLine();
if (line > 0)
return new ConfigException(className + ":" + line + ": " + msg);
else
return new ConfigException(className + "." + field.getName() + ": " + msg);
}
static ConfigException error(Method field, String msg)
{
// XXX: the field is for line numbers in the source, theoretically
String className = field.getDeclaringClass().getName();
int line = 0; //field.getLine();
if (line > 0)
return new ConfigException(className + ":" + line + ": " + msg);
else
return new ConfigException(className + "." + field.getName() + ": " + msg);
}
static ArrayList calculateColumns(com.caucho.amber.table.AmberTable mapTable,
EntityType type)
{
ArrayList columns = new ArrayList();
EntityType parentType = type;
ArrayList targetIdColumns;
targetIdColumns = type.getId().getColumns();
while (targetIdColumns.size() == 0) {
parentType = parentType.getParentType();
if (parentType == null)
break;
targetIdColumns = parentType.getId().getColumns();
}
for (com.caucho.amber.table.AmberColumn key : targetIdColumns) {
columns.add(mapTable.createForeignColumn(key.getName(), key));
}
return columns;
}
static ArrayList calculateColumns(com.caucho.amber.table.AmberTable mapTable,
String prefix,
EntityType type)
{
ArrayList columns = new ArrayList();
EntityType parentType = type;
ArrayList targetIdColumns;
targetIdColumns = type.getId().getColumns();
while (targetIdColumns.size() == 0) {
parentType = parentType.getParentType();
if (parentType == null)
break;
targetIdColumns = parentType.getId().getColumns();
}
for (com.caucho.amber.table.AmberColumn key : targetIdColumns) {
columns.add(mapTable.createForeignColumn(prefix + key.getName(), key));
}
return columns;
}
protected static String loc(Method method)
{
return method.getDeclaringClass().getSimpleName() + "." + method.getName() + ": ";
}
protected static String loc(Field field)
{
return field.getDeclaringClass().getSimpleName() + "." + field.getName() + ": ";
}
public static String toSqlName(String name)
{
return name; // name.toUpperCase(Locale.ENGLISH);
}
class AnnotationConfig {
private Annotation _annotation;
private Object _config;
public Annotation getAnnotation()
{
return _annotation;
}
public Object getConfig()
{
return _config;
}
public void setAnnotation(Annotation annotation)
{
_annotation = annotation;
}
public void setConfig(Object config)
{
_config = config;
}
public boolean isNull()
{
return (_annotation == null) && (_config == null);
}
public void reset()
{
_annotation = null;
_config = null;
}
public void reset(Class type, Class cl)
{
_annotation = type.getAnnotation(cl);
_config = null;
}
public void reset(AccessibleObject field, Class cl)
{
_annotation = field.getAnnotation(cl);
_config = null;
}
public EmbeddableConfig getEmbeddableConfig()
{
return (EmbeddableConfig) _config;
}
public EntityConfig getEntityConfig()
{
return (EntityConfig) _config;
}
public MappedSuperclassConfig getMappedSuperclassConfig()
{
return (MappedSuperclassConfig) _config;
}
public EntityListenersConfig getEntityListenersConfig()
{
return (EntityListenersConfig) _config;
}
public TableConfig getTableConfig() {
return (TableConfig) _config;
}
public SecondaryTableConfig getSecondaryTableConfig() {
return (SecondaryTableConfig) _config;
}
public IdClassConfig getIdClassConfig() {
return (IdClassConfig) _config;
}
public PostLoadConfig getPostLoadConfig() {
return (PostLoadConfig) _config;
}
public PrePersistConfig getPrePersistConfig() {
return (PrePersistConfig) _config;
}
public PostPersistConfig getPostPersistConfig() {
return (PostPersistConfig) _config;
}
public PreUpdateConfig getPreUpdateConfig() {
return (PreUpdateConfig) _config;
}
public PostUpdateConfig getPostUpdateConfig() {
return (PostUpdateConfig) _config;
}
public PreRemoveConfig getPreRemoveConfig() {
return (PreRemoveConfig) _config;
}
public PostRemoveConfig getPostRemoveConfig() {
return (PostRemoveConfig) _config;
}
public InheritanceConfig getInheritanceConfig() {
return (InheritanceConfig) _config;
}
public NamedQueryConfig getNamedQueryConfig() {
return (NamedQueryConfig) _config;
}
public NamedNativeQueryConfig getNamedNativeQueryConfig() {
return (NamedNativeQueryConfig) _config;
}
public SqlResultSetMappingConfig getSqlResultSetMappingConfig() {
return (SqlResultSetMappingConfig) _config;
}
public PrimaryKeyJoinColumnConfig getPrimaryKeyJoinColumnConfig() {
return (PrimaryKeyJoinColumnConfig) _config;
}
public DiscriminatorColumnConfig getDiscriminatorColumnConfig() {
return (DiscriminatorColumnConfig) _config;
}
public IdConfig getIdConfig() {
return (IdConfig) _config;
}
public EmbeddedIdConfig getEmbeddedIdConfig() {
return (EmbeddedIdConfig) _config;
}
public ColumnConfig getColumnConfig() {
return (ColumnConfig) _config;
}
public GeneratedValueConfig getGeneratedValueConfig() {
return (GeneratedValueConfig) _config;
}
public BasicConfig getBasicConfig() {
return (BasicConfig) _config;
}
public VersionConfig getVersionConfig() {
return (VersionConfig) _config;
}
public ManyToOneConfig getManyToOneConfig() {
return (ManyToOneConfig) _config;
}
public OneToOneConfig getOneToOneConfig() {
return (OneToOneConfig) _config;
}
public ManyToManyConfig getManyToManyConfig() {
return (ManyToManyConfig) _config;
}
public OneToManyConfig getOneToManyConfig() {
return (OneToManyConfig) _config;
}
public MapKeyConfig getMapKeyConfig() {
return (MapKeyConfig) _config;
}
public JoinTableConfig getJoinTableConfig() {
return (JoinTableConfig) _config;
}
public JoinColumnConfig getJoinColumnConfig() {
return (JoinColumnConfig) _config;
}
public AttributeOverrideConfig getAttributeOverrideConfig() {
return (AttributeOverrideConfig) _config;
}
// public AttributeOverridesConfig getAttributeOverridesConfig() {
// return (AttributeOverridesConfig) _config;
// }
public AssociationOverrideConfig getAssociationOverrideConfig() {
return (AssociationOverrideConfig) _config;
}
// public AssociationOverridesConfig getAssociationOverridesConfig() {
// return (AssociationOverridesConfig) _config;
// }
}
static {
// annotations allowed with a @Basic annotation
_basicAnnotations.add("javax.persistence.Basic");
_basicAnnotations.add("javax.persistence.Column");
_basicAnnotations.add("javax.persistence.Enumerated");
_basicAnnotations.add("javax.persistence.Lob");
_basicAnnotations.add("javax.persistence.Temporal");
// non-serializable types allowed with a @Basic annotation
_basicTypes.add("boolean");
_basicTypes.add("byte");
_basicTypes.add("char");
_basicTypes.add("short");
_basicTypes.add("int");
_basicTypes.add("long");
_basicTypes.add("float");
_basicTypes.add("double");
_basicTypes.add("[byte");
_basicTypes.add("[char");
_basicTypes.add("[java.lang.Byte");
_basicTypes.add("[java.lang.Character");
// annotations allowed with an @Id annotation
_idAnnotations.add("javax.persistence.Column");
_idAnnotations.add("javax.persistence.GeneratedValue");
_idAnnotations.add("javax.persistence.Id");
_idAnnotations.add("javax.persistence.SequenceGenerator");
_idAnnotations.add("javax.persistence.TableGenerator");
_idAnnotations.add("javax.persistence.Temporal");
// allowed with a @Id annotation
_idTypes.add("boolean");
_idTypes.add("byte");
_idTypes.add("char");
_idTypes.add("short");
_idTypes.add("int");
_idTypes.add("long");
_idTypes.add("float");
_idTypes.add("double");
_idTypes.add("java.lang.Boolean");
_idTypes.add("java.lang.Byte");
_idTypes.add("java.lang.Character");
_idTypes.add("java.lang.Short");
_idTypes.add("java.lang.Integer");
_idTypes.add("java.lang.Long");
_idTypes.add("java.lang.Float");
_idTypes.add("java.lang.Double");
_idTypes.add("java.lang.String");
_idTypes.add("java.util.Date");
_idTypes.add("java.sql.Date");
// annotations allowed with a @ManyToOne annotation
_manyToOneAnnotations.add("javax.persistence.ManyToOne");
_manyToOneAnnotations.add("javax.persistence.JoinColumn");
_manyToOneAnnotations.add("javax.persistence.JoinColumns");
// annotations allowed with a @OneToMany annotation
_oneToManyAnnotations.add("javax.persistence.OneToMany");
_oneToManyAnnotations.add("javax.persistence.JoinTable");
_oneToManyAnnotations.add("javax.persistence.MapKey");
_oneToManyAnnotations.add("javax.persistence.OrderBy");
// types allowed with a @OneToMany annotation
_oneToManyTypes.add("java.util.Collection");
_oneToManyTypes.add("java.util.List");
_oneToManyTypes.add("java.util.Set");
_oneToManyTypes.add("java.util.Map");
// annotations allowed with a @ManyToMany annotation
_manyToManyAnnotations.add("javax.persistence.ManyToMany");
_manyToManyAnnotations.add("javax.persistence.JoinTable");
_manyToManyAnnotations.add("javax.persistence.MapKey");
_manyToManyAnnotations.add("javax.persistence.OrderBy");
// types allowed with a @ManyToMany annotation
_manyToManyTypes.add("java.util.Collection");
_manyToManyTypes.add("java.util.List");
_manyToManyTypes.add("java.util.Set");
_manyToManyTypes.add("java.util.Map");
// annotations allowed with a @OneToOne annotation
_oneToOneAnnotations.add("javax.persistence.OneToOne");
_oneToOneAnnotations.add("javax.persistence.JoinColumn");
_oneToOneAnnotations.add("javax.persistence.JoinColumns");
// annotations allowed with a @ElementCollection annotation
_elementCollectionAnnotations.add("javax.persistence.ElementCollection");
// types allowed with an @ElementCollection annotation
_elementCollectionTypes.add("java.util.Collection");
_elementCollectionTypes.add("java.util.List");
_elementCollectionTypes.add("java.util.Set");
_elementCollectionTypes.add("java.util.Map");
// annotations allowed with a @Embedded annotation
_embeddedAnnotations.add("javax.persistence.Embedded");
_embeddedAnnotations.add("javax.persistence.AttributeOverride");
_embeddedAnnotations.add("javax.persistence.AttributeOverrides");
_embeddedAnnotations.add("javax.persistence.Column");
// annotations allowed with a @EmbeddedId annotation
_embeddedIdAnnotations.add("javax.persistence.EmbeddedId");
_embeddedIdAnnotations.add("javax.persistence.AttributeOverride");
_embeddedIdAnnotations.add("javax.persistence.AttributeOverrides");
// annotations allowed for a property
_propertyAnnotations.add("javax.persistence.Basic");
_propertyAnnotations.add("javax.persistence.Column");
_propertyAnnotations.add("javax.persistence.Id");
_propertyAnnotations.add("javax.persistence.Transient");
_propertyAnnotations.add("javax.persistence.OneToOne");
_propertyAnnotations.add("javax.persistence.ManyToOne");
_propertyAnnotations.add("javax.persistence.OneToMany");
_propertyAnnotations.add("javax.persistence.ManyToMany");
_propertyAnnotations.add("javax.persistence.JoinColumn");
_propertyAnnotations.add("javax.persistence.Embedded");
_propertyAnnotations.add("javax.persistence.EmbeddedId");
_propertyAnnotations.add("javax.persistence.Version");
// annotations allowed with a @Version annotation
_versionAnnotations.add("javax.persistence.Version");
_versionAnnotations.add("javax.persistence.Column");
_versionAnnotations.add("javax.persistence.Temporal");
// types allowed with a @Version annotation
_versionTypes.add("short");
_versionTypes.add("int");
_versionTypes.add("long");
_versionTypes.add("java.lang.Short");
_versionTypes.add("java.lang.Integer");
_versionTypes.add("java.lang.Long");
_versionTypes.add("java.sql.Timestamp");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy