This repository has been archived by the owner on Apr 13, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Konstantin Sobolev
committed
Nov 8, 2017
1 parent
ddfe8df
commit 8604a77
Showing
4 changed files
with
178 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
java/codegen/src/main/scala/ws/epigraph/java/service/assemblers/FieldAssemblersGen.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
* Copyright 2017 Sumo Logic | ||
* | ||
* 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 ws.epigraph.java.service.assemblers | ||
|
||
import java.nio.file.Path | ||
|
||
import ws.epigraph.compiler.CDatumType | ||
import ws.epigraph.java._ | ||
import ws.epigraph.java.NewlineStringInterpolator.NewlineHelper | ||
import ws.epigraph.java.JavaGenNames.{ln, lqn2} | ||
import ws.epigraph.java.service.projections.req.output.ReqOutputRecordModelProjectionGen | ||
import ws.epigraph.lang.Qn | ||
import ws.epigraph.util.JavaNames | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Konstantin Sobolev</a> | ||
*/ | ||
class FieldAssemblersGen(rag: RecordAsmGen, val ctx: GenContext) extends JavaGen { | ||
private val cType: CDatumType = JavaGenUtils.toCType(rag.g.op.`type`()) | ||
|
||
val namespace: Qn = rag.g.namespace | ||
|
||
val shortClassName: String = ln(cType) + "FieldAssemblers" | ||
|
||
val fullClassName: String = namespace.append(shortClassName).toString | ||
|
||
override def relativeFilePath: Path = JavaGenUtils.fqnToPath(namespace).resolve(shortClassName + ".java") | ||
|
||
private lazy val importManager: ImportManager = new ImportManager(namespace) | ||
|
||
private lazy val parentOpt: Option[FieldAssemblersGen] = rag.g.parentClassGenOpt.map( | ||
pg => pg.asInstanceOf[ReqOutputRecordModelProjectionGen].assemblerGen.fieldAssemblersGen | ||
) | ||
|
||
def methodName(fieldName: String): String = JavaNames.javaName(fieldName) | ||
|
||
case class AsmSupplier(fieldName: String, overloaded: Boolean, pg: ReqOutputRecordModelProjectionGen, importManager: ImportManager) { | ||
private val fieldPart = rag.fieldPart(fieldName).get | ||
|
||
val projectionType: importManager.ImportedName = importManager.use(fieldPart.fieldGen.fullClassName) | ||
|
||
val assemblerResultType: importManager.ImportedName = importManager.use( | ||
lqn2( | ||
fieldPart.fieldType, | ||
namespace.toString | ||
) | ||
) | ||
|
||
val resultTypeSuffix: String = if (fieldPart.isEntity) "" else ".Value" | ||
|
||
def gen: String = /*@formatter:off*/sn"""\ | ||
/** | ||
* Builds {@code $fieldName} field value | ||
* | ||
* @param dto data transfer object | ||
* @param projection request projection | ||
* @param ctx assembly context | ||
* | ||
* @return field value | ||
*/ | ||
public ${Imports.notNull}$assemblerResultType$resultTypeSuffix ${methodName(fieldName)}(${Imports.notNull}D dto, ${Imports.notNull}$projectionType projection, ${Imports.notNull}${Imports.assemblerContext} context); | ||
"""/*@formatter:on*/ | ||
} | ||
|
||
val asmSuppliers: Seq[AsmSupplier] = rag.g.fieldProjections.toSeq.map { case (fieldName, (parentGenOpt, _)) => | ||
AsmSupplier( | ||
fieldName, | ||
parentGenOpt.isDefined, | ||
parentGenOpt.getOrElse(rag.g).asInstanceOf[ReqOutputRecordModelProjectionGen], | ||
importManager | ||
) | ||
} | ||
|
||
|
||
override protected def generate: String = { | ||
if (rag.g.invalidParentClassGenerator) { | ||
throw new TryLaterException(s"Can't generate $fullClassName because parent projection wasn't created yet") | ||
} | ||
|
||
val parentImp = parentOpt.map(p => importManager.use(p.fullClassName)) | ||
|
||
closeImports() | ||
|
||
val extendsClause: String = parentImp.map(ip => s"extends $ip<D> ").getOrElse("") | ||
|
||
/*@formatter:off*/sn"""\ | ||
${JavaGenUtils.topLevelComment} | ||
package $namespace; | ||
|
||
${JavaGenUtils.generateImports(importManager.imports)} | ||
|
||
/** | ||
* Field assemblers for {@code ${ln(cType)}} type | ||
*/ | ||
${JavaGenUtils.generatedAnnotation(this)} | ||
public interface $shortClassName<D> $extendsClause{ | ||
${asmSuppliers.map(_.gen).mkString("\n")}\ | ||
}"""/*@formatter:on*/ | ||
} | ||
|
||
protected object Imports { | ||
val notNull: ImportManager.Imported = | ||
if (ctx.java8Annotations) importManager.use("org.jetbrains.annotations.NotNull").prepend("@").append(" ") else ImportManager.empty | ||
val nullable: ImportManager.Imported = | ||
if (ctx.java8Annotations) importManager.use("org.jetbrains.annotations.Nullable").prepend("@").append(" ") else ImportManager.empty | ||
val func: ImportManager.Imported = importManager.use("java.util.function.Function") | ||
val assembler: ImportManager.Imported = importManager.use("ws.epigraph.assembly.Asm") | ||
val assemblerContext: ImportManager.Imported = importManager.use("ws.epigraph.assembly.AsmContext") | ||
val _type: ImportManager.Imported = importManager.use("ws.epigraph.types.Type") | ||
val errValue: ImportManager.Imported = importManager.use("ws.epigraph.errors.ErrorValue") | ||
} | ||
|
||
protected def closeImports(): Unit = { | ||
val _ = Imports.assembler // cause lazy eval | ||
importManager.close() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,11 +29,15 @@ import scala.collection.immutable.ListMap | |
* @author <a href="mailto:[email protected]">Konstantin Sobolev</a> | ||
*/ | ||
class RecordAsmGen( | ||
override protected val g: ReqOutputRecordModelProjectionGen, | ||
override val g: ReqOutputRecordModelProjectionGen, | ||
val ctx: GenContext) extends JavaGen with ModelAsmGen { | ||
|
||
override protected type G = ReqOutputRecordModelProjectionGen | ||
|
||
lazy val fieldAssemblersGen: FieldAssemblersGen = new FieldAssemblersGen(this, ctx) | ||
|
||
override def children = Iterable(fieldAssemblersGen) | ||
|
||
import Imports._ | ||
|
||
case class FieldParts(field: CField, fieldGen: ReqProjectionGen) extends Comparable[FieldParts] { | ||
|
@@ -43,7 +47,7 @@ class RecordAsmGen( | |
|
||
def isEntity: Boolean = fieldType.kind == CTypeKind.ENTITY | ||
|
||
val fieldGenType: importManager.ImportedName = importManager.use(fieldGen.fullClassName) | ||
val fieldProjection: importManager.ImportedName = importManager.use(fieldGen.fullClassName) | ||
|
||
val assemblerResultType: importManager.ImportedName = importManager.use( | ||
lqn2( | ||
|
@@ -52,7 +56,7 @@ class RecordAsmGen( | |
) | ||
) | ||
|
||
def fieldAsmType: String = s"$assembler<? super D, ? super $fieldGenType, ? extends $assemblerResultType${ if (isEntity) "" else ".Value" }>" | ||
def fieldAsmType: String = s"$assembler<? super D, ? super $fieldProjection, ? extends $assemblerResultType${ if (isEntity) "" else ".Value" }>" | ||
|
||
def fbf: String = field.name + "FieldAsm" | ||
|
||
|
@@ -75,6 +79,8 @@ class RecordAsmGen( | |
FieldParts(f, fg.dataProjectionGen) | ||
}.toSeq.sorted | ||
|
||
def fieldPart(fieldName: String): Option[FieldParts] = fps.find(_.field.name == fieldName) | ||
|
||
private val obj = importManager.use("java.lang.Object") | ||
|
||
protected override lazy val defaultBuild: String = { | ||
|
@@ -94,6 +100,8 @@ ${if (hasMeta) s" b.setMeta(metaAsm.assemble(dto, p.meta(), ctx));\n" else ""}\ | |
} | ||
|
||
override protected def generate: String = { | ||
val fieldAssembersImp = importManager.use(fieldAssemblersGen.fullClassName) | ||
|
||
closeImports() | ||
|
||
/*@formatter:off*/sn"""\ | ||
|
@@ -106,33 +114,55 @@ ${JavaGenUtils.generateImports(importManager.imports)} | |
* Value assembler for {@code ${ln(cType)}} type, driven by request output projection | ||
*/ | ||
${JavaGenUtils.generatedAnnotation(this)} | ||
public class $shortClassName<D> implements $assembler<D, $notNull $projectionName, $notNull $t.Value> { | ||
${if (hasTails) s" private final $notNull $func<? super D, ? extends Type> typeExtractor;\n" else "" }\ | ||
public class $shortClassName<D> implements $assembler<D, $notNull$projectionName, $notNull$t.Value> { | ||
${if (hasTails) s" private final $notNull$func<? super D, ? extends Type> typeExtractor;\n" else "" }\ | ||
//field assemblers | ||
${fps.map { fp => s" private final $notNull ${fp.fieldAsmType} ${fp.fbf};"}.mkString("\n") }\ | ||
${if (hasTails) tps.map { tp => s" private final $notNull ${tp.assemblerType} ${tp.assembler};"}.mkString("\n //tail assemblers\n","\n","") else "" }\ | ||
${if (hasMeta) s" //meta assembler\n private final $notNull $metaAsmType metaAsm;" else ""} | ||
${fps.map { fp => s" private final $notNull${fp.fieldAsmType} ${fp.fbf};"}.mkString("\n") }\ | ||
${if (hasTails) tps.map { tp => s" private final $notNull${tp.assemblerType} ${tp.assembler};"}.mkString("\n //tail assemblers\n","\n","") else "" }\ | ||
${if (hasMeta) s" //meta assembler\n private final $notNull$metaAsmType metaAsm;" else ""} | ||
|
||
/** | ||
* Asm constructor | ||
* Asm constructor from individual field assemblers | ||
* | ||
${if (hasTails) s" * @param typeExtractor data type extractor, used to determine DTO type\n" else ""}\ | ||
${fps.map { fp => s" * @param ${fp.javadoc}"}.mkString("\n") }\ | ||
${if (hasTails) tps.map { tp => s" * @param ${tp.javadoc}"}.mkString("\n","\n","") else "" }\ | ||
${if (hasMeta) s"\n * @param metaAsm metadata assembler" else ""} | ||
*/ | ||
public $shortClassName( | ||
${if (hasTails) s" $notNull $func<? super D, ? extends Type> typeExtractor,\n" else "" }\ | ||
${fps.map { fp => s" $notNull ${fp.fieldAsmType} ${fp.fbf}"}.mkString(",\n") }\ | ||
${if (hasTails) tps.map { tp => s" $notNull ${tp.assemblerType} ${tp.assembler}"}.mkString(",\n", ",\n", "") else ""}\ | ||
${if (hasMeta) s",\n $notNull $metaAsmType metaAsm" else ""} | ||
${if (hasTails) s" $notNull$func<? super D, ? extends Type> typeExtractor,\n" else "" }\ | ||
${fps.map { fp => s" $notNull${fp.fieldAsmType} ${fp.fbf}"}.mkString(",\n") }\ | ||
${if (hasTails) tps.map { tp => s" $notNull${tp.assemblerType} ${tp.assembler}"}.mkString(",\n", ",\n", "") else ""}\ | ||
${if (hasMeta) s",\n $notNull$metaAsmType metaAsm" else ""} | ||
) { | ||
${if (hasTails) s" this.typeExtractor = typeExtractor;\n" else "" }\ | ||
${fps.map { fp => s" this.${fp.fbf} = ${fp.fbf};"}.mkString("\n") }\ | ||
${if (hasTails) tps.map { tp => s" this.${tp.assembler} = ${tp.assembler};"}.mkString("\n","\n","") else ""}\ | ||
${if (hasMeta) s"\n this.metaAsm = metaAsm;" else ""} | ||
} | ||
|
||
/** | ||
* Asm factory using field assemblers supplier object | ||
* | ||
${if (hasTails) s" * @param typeExtractor data type extractor, used to determine DTO type\n" else ""}\ | ||
* @param fieldAssemblers field assemblers supplier object | ||
${if (hasTails) tps.map { tp => s" * @param ${tp.javadoc}"}.mkString("","\n","\n") else "" }\ | ||
${if (hasMeta) s"\n * @param metaAsm metadata assembler\n" else ""}\ | ||
*/ | ||
public static <D> $shortClassName<D> fromFieldAssemblers( | ||
${if (hasTails) s" $notNull$func<? super D, ? extends Type> typeExtractor,\n" else "" }\ | ||
$notNull$fieldAssembersImp<D> fieldAssemblers\ | ||
${if (hasTails) tps.map { tp => s"$notNull${tp.assemblerType} ${tp.assembler}"}.mkString(",\n ", ",\n ","") else ""}\ | ||
${if (hasMeta) s",\n $notNull$metaAsmType metaAsm" else ""} | ||
) { | ||
return new $shortClassName<D>(\ | ||
${if (hasTails) s"\n typeExtractor," else "" }\ | ||
${fps.map {fp => s"\n fieldAssemblers::${fieldAssemblersGen.methodName(fp.field.name)}"}.mkString("", ",", if(hasTails||hasMeta) "," else "")}\ | ||
${if (hasTails) tps.map { tp => s" ${tp.assembler}"}.mkString("\n", ",\n", if(hasMeta) "," else "") else ""}\ | ||
${if (hasMeta) "\n metaAsm" else ""} | ||
); | ||
} | ||
|
||
/** | ||
* Assembles {@code $t} value from DTO | ||
* | ||
|
@@ -143,7 +173,7 @@ ${if (hasMeta) s"\n this.metaAsm = metaAsm;" else ""} | |
* @return {@code $t} value object | ||
*/ | ||
@Override | ||
public $notNull $t.Value assemble(D dto, $notNull $projectionName p, $notNull $assemblerContext ctx) { | ||
public $notNull$t.Value assemble(D dto, $notNull$projectionName p, $notNull$assemblerContext ctx) { | ||
if (dto == null) | ||
return $t.type.createValue($errValue.NULL); | ||
else ${if (hasTails) tailsBuild else nonTailsBuild} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters