/** * * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); You may not * use this file except in compliance with the License. You may obtain a copy of * the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.speedment.generator.standard.entity; import static com.speedment.common.codegen.constant.DefaultAnnotationUsage.OVERRIDE; import com.speedment.common.codegen.constant.DefaultJavadocTag; import static com.speedment.common.codegen.constant.DefaultJavadocTag.PARAM; import static com.speedment.common.codegen.constant.DefaultJavadocTag.RETURN; import com.speedment.common.codegen.constant.DefaultType; import com.speedment.common.codegen.constant.SimpleParameterizedType; import com.speedment.common.codegen.constant.SimpleType; import com.speedment.common.codegen.model.Constructor; import com.speedment.common.codegen.model.Enum; import com.speedment.common.codegen.model.EnumConstant; import com.speedment.common.codegen.model.Field; import com.speedment.common.codegen.model.File; import com.speedment.common.codegen.model.Import; import com.speedment.common.codegen.model.Interface; import com.speedment.common.codegen.model.Javadoc; import com.speedment.common.codegen.model.Method; import com.speedment.common.codegen.model.Value; import static com.speedment.common.codegen.util.Formatting.indent; import static com.speedment.common.codegen.util.Formatting.nl; import static com.speedment.common.codegen.util.Formatting.shortName; import com.speedment.common.function.OptionalBoolean; import com.speedment.common.injector.Injector; import com.speedment.common.injector.annotation.Inject; import static com.speedment.generator.standard.internal.util.ColumnUtil.usesOptional; import com.speedment.generator.standard.internal.util.EntityTranslatorSupport; import com.speedment.generator.standard.internal.util.FkHolder; import com.speedment.generator.translator.AbstractEntityAndManagerTranslator; import com.speedment.generator.translator.TranslatorSupport; import com.speedment.generator.translator.component.TypeMapperComponent; import com.speedment.runtime.config.Column; import com.speedment.runtime.config.Dbms; import com.speedment.runtime.config.Table; import com.speedment.runtime.config.identifier.ColumnIdentifier; import com.speedment.runtime.config.identifier.TableIdentifier; import com.speedment.runtime.config.util.DocumentDbUtil; import static com.speedment.runtime.config.util.DocumentUtil.Name.DATABASE_NAME; import static com.speedment.runtime.config.util.DocumentUtil.relativeName; import com.speedment.runtime.core.manager.Manager; import com.speedment.runtime.core.util.OptionalUtil; import com.speedment.runtime.typemapper.TypeMapper; import com.speedment.runtime.typemapper.primitive.PrimitiveTypeMapper; import java.lang.reflect.Type; import static java.util.Objects.requireNonNull; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; import java.util.stream.Stream; /** * * @author Emil Forslund * @author Per-Åke Minborg */ public final class GeneratedEntityTranslator extends AbstractEntityAndManagerTranslator<Interface> { public static final String IDENTIFIER_NAME = "Identifier"; @Inject private Injector injector; @Inject private TypeMapperComponent typeMappers; public GeneratedEntityTranslator(Table table) { super(table, Interface::of); } @Override protected Interface makeCodeGenModel(File file) { final Type tableIdentifierType = SimpleParameterizedType.create(TableIdentifier.class, getSupport().entityType()); final Enum identifierEnum = Enum.of(IDENTIFIER_NAME) .add(Field.of("columnName", String.class).private_().final_()) .add(Field.of("tableIdentifier", tableIdentifierType).private_().final_()) .add(SimpleParameterizedType.create(ColumnIdentifier.class, getSupport().entityType())) .add(Constructor.of() .add(Field.of("columnName", String.class)) .add("this.columnName\t = columnName;") .add("this.tableIdentifier\t = TableIdentifier.of(" + indent( "getDbmsName(), ", "getSchemaName(), ", "getTableName()" ) + ");") ) .add(Method.of("getDbmsName", String.class).public_() .add(OVERRIDE) .add(returnString(getSupport().dbmsOrThrow().getId())) ) .add(Method.of("getSchemaName", String.class).public_() .add(OVERRIDE) .add(returnString(getSupport().schemaOrThrow().getId())) ) .add(Method.of("getTableName", String.class).public_() .add(OVERRIDE) .add(returnString(getSupport().tableOrThrow().getId())) ) .add(Method.of("getColumnName", String.class).public_() .add(OVERRIDE) .add("return this.columnName;") ) .add(Method.of("asTableIdentifier", tableIdentifierType).public_() .add(OVERRIDE) .add("return this.tableIdentifier;") ); return newBuilder(file, getSupport().generatedEntityName()) /** * General */ .forEveryTable((intrf, col) -> intrf.public_().add(identifierEnum)) /** * Getters */ .forEveryColumn((intrf, col) -> { final Type retType = getterReturnType(typeMappers, col); intrf.add(Method.of(GETTER_METHOD_PREFIX + getSupport().typeName(col), retType) .set(Javadoc.of( "Returns the " + getSupport().variableName(col) + " of this " + getSupport().entityName() + ". The " + getSupport().variableName(col) + " field corresponds to the database column " + relativeName(col, Dbms.class, DATABASE_NAME) + "." ).add(RETURN.setText( "the " + getSupport().variableName(col) + " of this " + getSupport().entityName() )) ) ); }) /** * Setters */ .forEveryColumn((intrf, col) -> intrf.add(Method.of(SETTER_METHOD_PREFIX + getSupport().typeName(col), getSupport().entityType()) .add(Field.of(getSupport().variableName(col), typeMappers.get(col).getJavaType(col))) .set(Javadoc.of( "Sets the " + getSupport().variableName(col) + " of this " + getSupport().entityName() + ". The " + getSupport().variableName(col) + " field corresponds to the database column " + relativeName(col, Dbms.class, DATABASE_NAME) + "." ) .add(PARAM.setValue(getSupport().variableName(col)).setText("to set of this " + getSupport().entityName())) .add(RETURN.setText("this " + getSupport().entityName() + " instance"))) ) ) /** * Finders */ .forEveryColumn((intrf, col) -> EntityTranslatorSupport.getForeignKey( getSupport().tableOrThrow(), col ).ifPresent(fkc -> { final FkHolder fu = new FkHolder(injector, fkc.getParentOrThrow()); final TranslatorSupport<Table> fuSupport = fu.getForeignEmt().getSupport(); file.add(Import.of(fuSupport.entityType())); intrf.add(Method.of(FINDER_METHOD_PREFIX + getSupport().typeName(col), col.isNullable() ? DefaultType.optional(fuSupport.entityType()) : fuSupport.entityType() ) .set(Javadoc.of( "Queries the specified manager for the referenced " + fuSupport.entityName() + ". If no such " + fuSupport.entityName() + " exists, an {@code NullPointerException} will be thrown." ).add(DefaultJavadocTag.PARAM.setValue("foreignManager").setText("the manager to query for the entity")) .add(DefaultJavadocTag.RETURN.setText("the foreign entity referenced")) ) .add(Field.of("foreignManager", SimpleParameterizedType.create( Manager.class, fuSupport.entityType() ))) ); }) ) /** * Fields */ .forEveryColumn((intrf, col) -> { final EntityTranslatorSupport.ReferenceFieldType ref = EntityTranslatorSupport.getReferenceFieldType( file, getSupport().tableOrThrow(), col, getSupport().entityType(), injector ); final Type entityType = getSupport().entityType(); final String shortEntityName = getSupport().entityName(); file.add(Import.of(entityType)); final String constant = getSupport().namer().javaStaticFieldName(col.getJavaName()); identifierEnum.add(EnumConstant.of(constant).add(Value.ofText(col.getId()))); // Begin building the field value parameters. final Stream.Builder<String> fieldParams = Stream.builder(); fieldParams.add("Identifier." + constant + ","); // Add getter method reference if (usesOptional(col)) { fieldParams.add("o -> OptionalUtil.unwrap(o." + GETTER_METHOD_PREFIX + getSupport().typeName(col) + "()),"); file.add(Import.of(OptionalUtil.class)); } else { fieldParams.add(shortEntityName + "::get" + getSupport().typeName(col) + ","); } // Add setter method reference fieldParams.add(shortEntityName + "::" + SETTER_METHOD_PREFIX + getSupport().typeName(col) + ","); // Add the foreign key method reference EntityTranslatorSupport.getForeignKey(getSupport().tableOrThrow(), col) .ifPresent(fkc -> { final FkHolder fu = new FkHolder(injector, fkc.getParentOrThrow()); final TranslatorSupport<Table> fuSupport = fu.getForeignEmt().getSupport(); fieldParams.add(fuSupport.entityName() + "." + fuSupport.namer().javaStaticFieldName( fu.getForeignColumn().getJavaName() ) + "," ); }); // Add type mapper if (col.getTypeMapper().isPresent()) { final String typeMapper = col.getTypeMapper().get(); if (PrimitiveTypeMapper.class.getName().equals(typeMapper)) { file.add(Import.of(TypeMapper.class)); fieldParams.add("TypeMapper.primitive(), "); } else { file.add(Import.of(SimpleType.create(typeMapper))); fieldParams.add("new " + shortName(typeMapper) + "(), "); } } else { fieldParams.add("TypeMapper.identity(), "); file.add(Import.of(TypeMapper.class)); } // Add the 'unique' boolean to the end fieldParams.add(Boolean.toString(DocumentDbUtil.isUnique(col))); intrf.add(Field.of(getSupport().namer().javaStaticFieldName(col.getJavaName()), ref.type) .final_() .set(Value.ofReference( shortName(ref.type.getTypeName()) + ".create(" + nl() + indent( fieldParams.build().toArray(String[]::new) ) + nl() + ")" )) .set(Javadoc.of( "This Field corresponds to the {@link " + shortEntityName + "} field that can be obtained using the " + "{@link " + shortEntityName + "#get" + getSupport().typeName(col) + "()} method." ))); }) .build(); } @Override protected String getJavadocRepresentText() { return "The generated base for the {@link " + getSupport().entityType().getTypeName() + "}-interface representing entities of the {@code " + getDocument().getId() + "}-table in the database."; } @Override protected String getClassOrInterfaceName() { return getSupport().generatedEntityName(); } @Override public boolean isInGeneratedPackage() { return true; } static Type getterReturnType(TypeMapperComponent typeMappers, Column col) { final Type retType; final Type type = typeMappers.get(col).getJavaType(col); if (usesOptional(col)) { if (type.equals(Integer.class)) { retType = OptionalInt.class; } else if (type.equals(Long.class)) { retType = OptionalLong.class; } else if (type.equals(Double.class)) { retType = OptionalDouble.class; } else if (type.equals(Boolean.class)) { retType = OptionalBoolean.class; } else { retType = SimpleParameterizedType.create(Optional.class, type); } } else { retType = type; } return retType; } private String returnString(String s) { requireNonNull(s); return "return \""+s+"\";"; } }