diff --git a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/entity/GeneratedEntityImplTranslator.java b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/entity/GeneratedEntityImplTranslator.java
index 01ef00c1e7..1529a8f523 100644
--- a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/entity/GeneratedEntityImplTranslator.java
+++ b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/entity/GeneratedEntityImplTranslator.java
@@ -68,6 +68,16 @@ protected Class makeCodeGenModel(File file) {
return newBuilder(file, getSupport().generatedEntityImplName())
+ /**
+ * Class details
+ */
+ .forEveryTable((clazz, table) -> {
+ clazz.public_()
+ .abstract_()
+ .add(getSupport().entityType())
+ .add(Constructor.of().protected_());
+ })
+
/**
* Getters
*/
@@ -99,7 +109,7 @@ protected Class makeCodeGenModel(File file) {
.forEveryColumn((clazz, col) -> {
clazz
.add(Method.of(SETTER_METHOD_PREFIX + getSupport().typeName(col), getSupport().entityType())
- .public_().final_()
+ .public_()
.add(OVERRIDE)
.add(fieldFor(col))
.add("this." + getSupport().variableName(col) + " = " + getSupport().variableName(col) + ";")
@@ -149,10 +159,7 @@ protected Class makeCodeGenModel(File file) {
);
});
})
-
- /**
- * Class details
- */
+
// We need to make it POST_MAKE because other plugins might add fields
.forEveryTable(Phase.POST_MAKE, (clazz, table) -> {
clazz
@@ -160,11 +167,7 @@ protected Class makeCodeGenModel(File file) {
.add(equalsMethod())
.add(hashCodeMethod());
})
- .build()
- .public_()
- .abstract_()
- .add(getSupport().generatedEntityType())
- .add(Constructor.of().protected_());
+ .build();
}
diff --git a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/internal/util/GenerateMethodBodyUtil.java b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/internal/util/GenerateMethodBodyUtil.java
index edc13ed28d..705874de57 100644
--- a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/internal/util/GenerateMethodBodyUtil.java
+++ b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/internal/util/GenerateMethodBodyUtil.java
@@ -95,8 +95,10 @@ public interface ReadFromResultSet {
String readFromResultSet(File file, Column c, AtomicInteger position);
}
- public static String[] generateNewEntityFromBody(ReadFromResultSet readFromResultSet, TranslatorSupport
support, File file, Supplier> columnsSupplier) {
+ public static String[] generateApplyResultSetBody(ReadFromResultSet readFromResultSet, TranslatorSupport support, File file, Supplier> columnsSupplier) {
+ file.add(Import.of(SQLException.class));
+
final List rows = new LinkedList<>();
rows.add("final " + support.entityName() + " entity = manager." + ENTITY_CREATE_METHOD_NAME + "();");
@@ -110,7 +112,7 @@ public static String[] generateNewEntityFromBody(ReadFromResultSet readFromResul
});
rows.add("try " + block(streamBuilder.build()));
- rows.add("catch (" + SQLException.class.getSimpleName() + " sqle) " + block(
+ rows.add("catch (final " + SQLException.class.getSimpleName() + " sqle) " + block(
"throw new " + SpeedmentException.class.getSimpleName() + "(sqle);"
));
rows.add("return entity;");
diff --git a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/manager/GeneratedSqlAdapterTranslator.java b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/manager/GeneratedSqlAdapterTranslator.java
index aebfc0e1ad..b5955d553d 100644
--- a/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/manager/GeneratedSqlAdapterTranslator.java
+++ b/generator-parent/generator-standard/src/main/java/com/speedment/generator/standard/manager/GeneratedSqlAdapterTranslator.java
@@ -24,7 +24,6 @@
import com.speedment.common.codegen.model.File;
import com.speedment.common.codegen.model.Import;
import com.speedment.common.codegen.model.Method;
-import com.speedment.common.injector.Injector;
import com.speedment.common.injector.annotation.Inject;
import com.speedment.generator.translator.AbstractEntityAndManagerTranslator;
import com.speedment.generator.translator.TranslatorSupport;
@@ -39,47 +38,45 @@
import java.lang.reflect.Type;
import java.sql.ResultSet;
-import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Stream;
import com.speedment.common.codegen.internal.model.value.ReferenceValue;
-import static com.speedment.common.codegen.internal.util.Formatting.indent;
import com.speedment.common.injector.State;
import com.speedment.common.injector.annotation.ExecuteBefore;
-import com.speedment.common.injector.annotation.WithState;
-import com.speedment.runtime.config.util.DocumentDbUtil;
import com.speedment.runtime.core.exception.SpeedmentException;
import static com.speedment.runtime.core.util.DatabaseUtil.dbmsTypeOf;
-import static com.speedment.generator.standard.internal.util.ColumnUtil.usesOptional;
-import static com.speedment.generator.standard.internal.util.GenerateMethodBodyUtil.generateNewEntityFromBody;
import com.speedment.generator.translator.component.TypeMapperComponent;
+import com.speedment.generator.translator.exception.SpeedmentTranslatorException;
import com.speedment.runtime.config.Project;
import com.speedment.runtime.config.identifier.TableIdentifier;
+import com.speedment.runtime.config.trait.HasEnabled;
import com.speedment.runtime.core.component.sql.SqlPersistenceComponent;
import com.speedment.runtime.core.component.sql.SqlStreamSupplierComponent;
+import com.speedment.runtime.core.component.sql.SqlTypeMapperHelper;
+import com.speedment.runtime.typemapper.TypeMapper;
import static java.util.stream.Collectors.joining;
+import static com.speedment.generator.standard.internal.util.GenerateMethodBodyUtil.generateApplyResultSetBody;
/**
*
- * @author Emil Forslund
+ * @author Emil Forslund
+ * @since 3.0.1
*/
public final class GeneratedSqlAdapterTranslator extends AbstractEntityAndManagerTranslator {
- public final static String ENTITY_COPY_METHOD_NAME = "entityCopy",
- ENTITY_CREATE_METHOD_NAME = "entityCreate",
- FIELDS_METHOD = "fields",
+ public final static String
+ CREATE_HELPERS_METHOD_NAME = "createHelpers",
+ INSTALL_METHOD_NAME = "installMethodName",
+ ENTITY_COPY_METHOD_NAME = "entityCopy",
+ ENTITY_CREATE_METHOD_NAME = "entityCreate",
+ FIELDS_METHOD = "fields",
PRIMARY_KEYS_FIELDS_METHOD = "primaryKeyFields";
- private @Inject
- ResultSetMapperComponent resultSetMapperComponent;
- private @Inject
- DbmsHandlerComponent dbmsHandlerComponent;
- private @Inject
- TypeMapperComponent typeMappers;
- private @Inject
- Injector injector;
+ private @Inject ResultSetMapperComponent resultSetMapperComponent;
+ private @Inject DbmsHandlerComponent dbmsHandlerComponent;
+ private @Inject TypeMapperComponent typeMapperComponent;
public GeneratedSqlAdapterTranslator(Table table) {
super(table, Class::of);
@@ -87,55 +84,95 @@ public GeneratedSqlAdapterTranslator(Table table) {
@Override
protected Class makeCodeGenModel(File file) {
- file.add(Import.of(Project.class));
+ final Type tableIdentifierType = SimpleParameterizedType
+ .create(TableIdentifier.class, getSupport().entityType());
+
return newBuilder(file, getClassOrInterfaceName())
.forEveryTable((clazz, table) -> {
- clazz
- .public_()
- .abstract_()
- .add(Field.of("manager", getSupport().managerType()).add(inject()).private_())
- .add(Field.of("tableIdentifier", SimpleParameterizedType.create(TableIdentifier.class, getSupport().entityType())).private_().final_())
- .add(Field.of("project", Project.class).private_())
- .add(Method.of("createHelpers", void.class).add(withExecuteBefore(file))
- .add(Field.of("projectComponent", ProjectComponent.class))
- .add("this.project = projectComponent.getProject();")
+ final Method createHelpers = Method.of(CREATE_HELPERS_METHOD_NAME, void.class)
+ .add(withExecuteBefore(file))
+ .add(Field.of("projectComponent", ProjectComponent.class))
+ .add("final Project project = projectComponent.getProject();");
+
+ clazz.public_().abstract_()
+
+ // Generate conxtructor
+ .add(Constructor.of().protected_()
+ .add("this.tableIdentifier = "
+ + TableIdentifier.class.getSimpleName() + ".of("
+ + Stream.of(
+ getSupport().dbmsOrThrow().getName(),
+ getSupport().schemaOrThrow().getName(),
+ getSupport().tableOrThrow().getName()
+ ).map(s -> "\"" + s + "\"").collect(joining(", "))
+ + ");")
)
- .add(Method.of("install", void.class).add(withExecuteBefore(file))
- .add("")
- .add(Field.of("manager", getSupport().managerType()))
+
+ // Generate member fields
+ .add(Field.of("tableIdentifier", tableIdentifierType).private_().final_())
+ .add(Field.of("manager", getSupport().managerType()).add(inject()).private_())
+
+ // Generate methods
+ .add(Method.of(INSTALL_METHOD_NAME, void.class).add(withExecuteBefore(file))
.add(Field.of("streamSupplierComponent", SqlStreamSupplierComponent.class))
.add(Field.of("persistenceComponent", SqlPersistenceComponent.class))
.add("streamSupplierComponent.install(tableIdentifier, this::apply);")
.add("persistenceComponent.install(tableIdentifier);")
)
- .add(Constructor.of().protected_()
- // .add("this.tableIdentifier = "+TableIdentifier.class.getSimpleName()+".of(\\\"\" + getSupport().dbmsOrThrow().getName() + \"\\\");
- .add("this.tableIdentifier = " + TableIdentifier.class.getSimpleName() + ".of("
- + Stream.of(getSupport().dbmsOrThrow().getName(), getSupport().schemaOrThrow().getName(), getSupport().tableOrThrow().getName())
- .map(s -> "\"" + s + "\"").collect(joining(", "))
- + ");")
- )
- .add(generateNewEntityFrom(getSupport(), file, table::columns));
+
+ .add(generateApplyResultSet(getSupport(), file, table::columns))
+
+ .call(() -> {
+ // Operate on enabled columns that has a type mapper
+ // that is not either empty, an identity mapper or a
+ // primitive mapper.
+ table.columns()
+ .filter(HasEnabled::test)
+ .filter(c -> c.getTypeMapper()
+ .filter(tm -> !"".equals(tm))
+ .filter(tm -> !tm.equals(TypeMapper.identity().getClass().getName()))
+ .filter(tm -> !tm.equals(TypeMapper.primitive().getClass().getName()))
+ .isPresent()
+ ).forEachOrdered(col -> {
+ // If the method has not yet been added, add it
+ if (clazz.getMethods().stream()
+ .map(Method::getName)
+ .noneMatch(CREATE_HELPERS_METHOD_NAME::equals)) {
+ file.add(Import.of(Project.class));
+ clazz.add(createHelpers);
+ }
+
+ // Append the line for this helper to the method
+ final String tmName = col.getTypeMapper().get();
+ final TypeMapper, ?> tm = typeMapperComponent.get(col);
+
+ final String tmsName = helperName(col);
+ final Type tmsType = SimpleParameterizedType.create(
+ SqlTypeMapperHelper.class,
+ typeMapperComponent.findDatabaseTypeOf(tm)
+ .orElseThrow(() -> new SpeedmentTranslatorException(
+ "Could not find appropriate " +
+ "database type for column '" + col +
+ "'."
+ )),
+ tm.getJavaType(col)
+ );
+
+ clazz.add(Field.of(tmsName, tmsType).private_());
+
+ createHelpers
+ .add(tmsName + " = " + SqlTypeMapperHelper.class.getSimpleName() +
+ ".create(project, " + getSupport().entityName() +
+ "." + getSupport().namer().javaStaticFieldName(col.getJavaName()) +
+ ", " + getSupport().entityName() + ".class);"
+ );
+ });
+ })
+ ;
})
- .build()
- .call(i -> file.add(Import.of(getSupport().entityImplType())));
+ .build();
}
-// private Method generateApplyMethod(File file, Table table) {
-// return Method.of("apply", getSupport().entityType()).protected_()
-// .add("final " + getSupport().entityName() + " entity = manager.entityCreate();")
-// .add("try {")
-// .add(indent(fieldsss(table)))
-// .add("} catch (final SQLException sqle) {")
-// .add(indent("throw new SpeedmentException(sqle);"))
-// .add("}")
-// .add("return entity;");
-// }
-
-// private String[] fieldsss(Table table) {
-// throw new UnsupportedOperationException("Todo");
-// }
-
@Override
protected String getJavadocRepresentText() {
return "The generated Sql Adapter for a {@link "
@@ -156,18 +193,15 @@ public Type getImplType() {
return getSupport().managerImplType();
}
- private Method generateNewEntityFrom(TranslatorSupport support, File file, Supplier> columnsSupplier) {
+ private Method generateApplyResultSet(TranslatorSupport support, File file, Supplier> columnsSupplier) {
return Method.of("apply", support.entityType())
.protected_()
- .add(SQLException.class)
.add(SpeedmentException.class)
.add(Field.of("resultSet", ResultSet.class))
- .add(generateNewEntityFromBody(this::readFromResultSet, support, file, columnsSupplier));
+ .add(generateApplyResultSetBody(this::readFromResultSet, support, file, columnsSupplier));
}
private String readFromResultSet(File file, Column c, AtomicInteger position) {
-
- final TranslatorSupport support = new TranslatorSupport<>(injector, c.getParentOrThrow());
final Dbms dbms = c.getParentOrThrow().getParentOrThrow().getParentOrThrow();
final ResultSetMapping> mapping = resultSetMapperComponent.apply(
@@ -175,60 +209,34 @@ private String readFromResultSet(File file, Column c, AtomicInteger position) {
c.findDatabaseType()
);
- final boolean isIdentityMapper = !c.getTypeMapper().isPresent();
-
- file.add(Import.of(DocumentDbUtil.class));
+ final java.lang.Class> typeMapperClass = typeMapperComponent.get(c).getClass();
+ final boolean isCustomTypeMapper = c.getTypeMapper().isPresent()
+ && !TypeMapper.identity().getClass().isAssignableFrom(typeMapperClass)
+ && !TypeMapper.primitive().getClass().isAssignableFrom(typeMapperClass);
final StringBuilder sb = new StringBuilder();
- if (!isIdentityMapper) {
- sb
- .append(typeMapperName(support, c))
- .append(".toJavaType(DocumentDbUtil.referencedColumn(project, ")
- .append(support.entityName())
- .append(".")
- .append(support.namer().javaStaticFieldName(c.getJavaName()))
- .append(".identifier()), manager.getEntityClass(), ");
+ if (isCustomTypeMapper) {
+ sb.append(helperName(c)).append(".apply(");
}
+
final String getterName = "get" + mapping.getResultSetMethodName(dbms);
-
- final boolean isResultSetMethod = Stream.of(ResultSet.class.getMethods())
- .map(java.lang.reflect.Method::getName)
- .anyMatch(getterName::equals);
-
- final boolean isResultSetMethodReturnsPrimitive = Stream.of(ResultSet.class.getMethods())
- .filter(m -> m.getName().equals(getterName))
- .anyMatch(m -> m.getReturnType().isPrimitive());
-
- if (isResultSetMethod && !(usesOptional(c) && isResultSetMethodReturnsPrimitive)) {
- sb
- .append("resultSet.")
- .append("get")
- .append(mapping.getResultSetMethodName(dbms))
- .append("(").append(position.getAndIncrement()).append(")");
- } else {
+ if (c.isNullable()) {
+
file.add(Import.of(ResultSetUtil.class).static_().setStaticMember("*"));
- sb
- .append("get")
- .append(mapping.getResultSetMethodName(dbms))
- .append("(resultSet, ")
+ sb.append(getterName).append("(resultSet, ")
.append(position.getAndIncrement()).append(")");
+ } else {
+ sb.append("resultSet.").append(getterName)
+ .append("(").append(position.getAndIncrement()).append(")");
}
- if (!isIdentityMapper) {
+
+ if (isCustomTypeMapper) {
sb.append(")");
}
return sb.toString();
}
- private static String typeMapperName(TranslatorSupport support, Column col) {
- return support.entityName() + "." + support.namer().javaStaticFieldName(col.getJavaName()) + ".typeMapper()";
- }
-
-// private static boolean isPrimaryKey(Column column) {
-// return column.getParentOrThrow().findPrimaryKeyColumn(column.getName()).isPresent();
-// }
-
-
private AnnotationUsage withExecuteBefore(File file) {
file.add(Import.of(State.class).static_().setStaticMember("RESOLVED"));
return AnnotationUsage.of(ExecuteBefore.class).set(new ReferenceValue("RESOLVED"));
@@ -237,5 +245,30 @@ private AnnotationUsage withExecuteBefore(File file) {
private AnnotationUsage inject() {
return AnnotationUsage.of(Inject.class);
}
-
-}
+
+ private String helperName(Column column) {
+ return getSupport().namer()
+ .javaVariableName(column.getJavaName()) + "Helper";
+ }
+
+ private enum TypeMapperType {
+ IDENTITY, PRIMITIVE, OTHER;
+
+ static TypeMapperType of(TypeMapperComponent mappers, Column col) {
+
+ if (!col.getTypeMapper().isPresent()) {
+ return IDENTITY;
+ }
+
+ final TypeMapper, ?> mapper = mappers.get(col);
+
+ if (TypeMapper.identity().getClass().isAssignableFrom(mapper.getClass())) {
+ return IDENTITY;
+ } else if (TypeMapper.primitive().getClass().isAssignableFrom(mapper.getClass())) {
+ return PRIMITIVE;
+ } else {
+ return OTHER;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/component/TypeMapperComponent.java b/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/component/TypeMapperComponent.java
index f71d4a571f..a5cf3fef1b 100644
--- a/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/component/TypeMapperComponent.java
+++ b/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/component/TypeMapperComponent.java
@@ -75,4 +75,22 @@ public interface TypeMapperComponent {
* @return the mapper class
*/
TypeMapper, ?> get(Column column);
+
+ /**
+ * Locates the specified type mapper in the store and returns the database
+ * type that it is been installed for. If the same {@code TypeMapper} has
+ * been installed for multiple classes, the returned class is unspecified
+ * but will be one of the installed types.
+ *
+ * If the specified type mapper has not been installed in this component,
+ * an empty optional is returned.
+ *
+ * Warning! This is potentially a very expensive operation.
+ *
+ * @param the database type
+ * @param the java type
+ * @param typeMapper the type mapper to locate
+ * @return a database type for which the mapper is used
+ */
+ Optional> findDatabaseTypeOf(TypeMapper typeMapper);
}
\ No newline at end of file
diff --git a/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/internal/component/TypeMapperComponentImpl.java b/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/internal/component/TypeMapperComponentImpl.java
index eb447d97f0..377fa3b094 100644
--- a/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/internal/component/TypeMapperComponentImpl.java
+++ b/generator-parent/generator-translator/src/main/java/com/speedment/generator/translator/internal/component/TypeMapperComponentImpl.java
@@ -23,6 +23,7 @@
import com.speedment.runtime.config.Column;
import com.speedment.runtime.typemapper.TypeMapper;
import com.speedment.runtime.typemapper.bigdecimal.BigDecimalToDouble;
+import com.speedment.runtime.typemapper.exception.SpeedmentTypeMapperException;
import com.speedment.runtime.typemapper.integer.IntegerZeroOneToBooleanMapper;
import com.speedment.runtime.typemapper.largeobject.ClobToStringMapper;
import com.speedment.runtime.typemapper.primitive.PrimitiveTypeMapper;
@@ -151,4 +152,34 @@ public void install(Class> databaseType, Supplier> typeMapper
}).orElseGet(TypeMapper::identity)
);
}
+
+ @Override
+ public Optional> findDatabaseTypeOf(TypeMapper typeMapper) {
+ final Class> needle = typeMapper.getClass();
+ return mappers.entrySet().stream()
+ .filter(e -> e.getValue().stream()
+ .map(Supplier>::get)
+ .map(TypeMapper::getClass)
+ .anyMatch(needle::equals)
+ )
+ .map(Map.Entry::getKey)
+ .findAny()
+ .map(key -> {
+ try {
+ @SuppressWarnings("unchecked")
+ final Class result = (Class) Class.forName(key);
+ return result;
+ } catch (final ClassNotFoundException ex) {
+ throw new SpeedmentTranslatorException(
+ "Could not find installed type mapper key '" + key +
+ "' on class path.", ex
+ );
+ } catch (final ClassCastException ex) {
+ throw new SpeedmentTranslatorException(
+ "An error occured when an installed type mapper key " +
+ "was thrown to the expected type '" + key + "'.", ex
+ );
+ }
+ });
+ }
}
\ No newline at end of file
diff --git a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/builder/ReferenceStreamBuilder.java b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/builder/ReferenceStreamBuilder.java
index 86023d167d..aff368d5b9 100644
--- a/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/builder/ReferenceStreamBuilder.java
+++ b/runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/internal/stream/builder/ReferenceStreamBuilder.java
@@ -433,5 +433,4 @@ public Spliterator spliterator() {
throw new UnsupportedOperationException(UNSUPPORTED_BECAUSE_OF_CLOSE_MAY_NOT_BE_CALLED);
//return streamTerminator.spliterator(pipeline());
}
-
-}
+}
\ No newline at end of file