MapEntryTableNamingStrategy.java
package org.codefilarete.stalactite.dsl.naming;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.codefilarete.reflection.AccessorDefinition;
import org.codefilarete.stalactite.dsl.MappingConfigurationException;
import org.codefilarete.stalactite.sql.ddl.structure.Column;
import org.codefilarete.stalactite.sql.ddl.structure.PrimaryKey;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.tool.Reflections;
import org.codefilarete.tool.Strings;
import static org.codefilarete.tool.Reflections.GET_SET_PREFIX_REMOVER;
import static org.codefilarete.tool.Reflections.IS_PREFIX_REMOVER;
/**
* Table naming strategy contract for {@link java.util.Map} element table
*
* @author Guillaume Mary
*/
public interface MapEntryTableNamingStrategy {
/**
* Gives association table name
* @param accessorDefinition a representation of the method (getter or setter) that gives the map to be persisted
* @return table name for {@link java.util.Map} element table
*/
String giveTableName(AccessorDefinition accessorDefinition, Class<?> keyType, Class<?> valueType);
<RIGHTTABLE extends Table<RIGHTTABLE>, RIGHTID> Map<Column<RIGHTTABLE, ?>, String>
giveMapKeyColumnNames(AccessorDefinition accessorDefinition,
Class entityType,
PrimaryKey<RIGHTTABLE, RIGHTID> rightPrimaryKey,
Set<String> existingColumnNames);
MapEntryTableNamingStrategy DEFAULT = new DefaultMapEntryTableNamingStrategy();
/**
* Default implementation of the {@link MapEntryTableNamingStrategy} interface.
* Will use relation property name for it, prefixed with source table name.
* For instance: for a Country entity with the getCities() getter to retrieve country cities,
* the association table will be named "Country_cities".
* If property cannot be deduced from getter (it doesn't start with "get") then target table name will be used, suffixed by "s".
* For instance: for a Country entity with the giveCities() getter to retrieve country cities,
* the association table will be named "Country_citys".
*/
class DefaultMapEntryTableNamingStrategy implements MapEntryTableNamingStrategy {
@Override
public String giveTableName(AccessorDefinition accessorDefinition, Class<?> keyType, Class<?> valueType) {
String suffix = Reflections.onJavaBeanPropertyWrapperNameGeneric(accessorDefinition.getName(), accessorDefinition.getName(),
GET_SET_PREFIX_REMOVER.andThen(Strings::uncapitalize),
GET_SET_PREFIX_REMOVER.andThen(Strings::uncapitalize),
IS_PREFIX_REMOVER.andThen(Strings::uncapitalize),
methodName -> methodName); // on non-compliant Java Bean Naming Convention, method name is returned as table name
return accessorDefinition.getDeclaringClass().getSimpleName() + "_" + suffix;
}
@Override
public <RIGHTTABLE extends Table<RIGHTTABLE>, RIGHTID> Map<Column<RIGHTTABLE, ?>, String>
giveMapKeyColumnNames(AccessorDefinition accessorDefinition,
Class entityType,
PrimaryKey<RIGHTTABLE, RIGHTID> rightPrimaryKey,
Set<String> existingColumnNames) {
Map<Column<RIGHTTABLE, ?>, String> result = new HashMap<>();
Set<String> existingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
existingColumns.addAll(existingColumnNames);
// columns pointing to right table get a name that contains accessor definition name
String rightSideColumnNamePrefix = entityType.getSimpleName();
rightPrimaryKey.getColumns().forEach(column -> {
String rightColumnName = Strings.uncapitalize(rightSideColumnNamePrefix + "_" + column.getName());
if (existingColumns.contains(rightColumnName)) {
throw new MappingConfigurationException("Identical column names in association table of collection "
+ accessorDefinition + " : " + rightColumnName);
}
result.put(column, rightColumnName);
});
return result;
}
}
}