Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@Attribute annotationへの対応 #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Slim3ModelMetaGeneratorPlugin : コンパイラプラグイン本体
Slim3ModelTest : モデルからModelMetaを生成するテストプロジェクト

> cd Slim3ModelMetaGeneratorPlugin
> sbt package
> sbt publish-local

> cd ../Slim3ModelTest
> sbt compile
Expand All @@ -30,4 +30,5 @@ http://sites.google.com/site/slim3appengine/slim3-datastore

* GAEで動作を確認
* Scalatraと連携
* Cipher Textのサポート https://sites.google.com/site/slim3documentja/documents/slim3-datastore/defining-data-classes#TOC-Cipher-Text

7 changes: 7 additions & 0 deletions Slim3ModelMetaGeneratorPlugin/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
organization := "scalatohoku.slim3"

name := "Slim3ModelMetaGeneratorPlugin"

scalaVersion := "2.9.1"

libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.9.1"
8 changes: 0 additions & 8 deletions Slim3ModelMetaGeneratorPlugin/project/build.properties

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion Slim3ModelMetaGeneratorPlugin/sbt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/sh
java -Drun.mode=production -XX:+CMSClassUnloadingEnabled -Xmx256M -Xss2M -XX:MaxPermSize=128m -jar `dirname $0`/sbt-launch-0.7.4.jar "$@"
java -Drun.mode=production -XX:+CMSClassUnloadingEnabled -Xmx256M -Xss2M -XX:MaxPermSize=128m -jar `dirname $0`/sbt-launch-0.10.1.jar "$@"
Binary file not shown.
Binary file removed Slim3ModelMetaGeneratorPlugin/sbt-launch-0.7.4.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion Slim3ModelMetaGeneratorPlugin/sbt.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
set SCRIPT_DIR=%~dp0
java -XX:+CMSClassUnloadingEnabled -Xmx256M -Xss2M -XX:MaxPermSize=128m -cp target\classes -jar "%SCRIPT_DIR%sbt-launch-0.7.4.jar" %*
java -XX:+CMSClassUnloadingEnabled -Xmx256M -Xss2M -XX:MaxPermSize=128m -cp target\classes -jar "%SCRIPT_DIR%sbt-launch-0.10.1.jar" %*
Original file line number Diff line number Diff line change
@@ -1,48 +1,129 @@
package scalatohoku.slim3

class MetaGen(val packageName:String,val modelName:String) {
val props = new scala.collection.mutable.HashMap[String,String] // name -> className
class MetaGen(val packageName: String, val modelName: String) {
val props = new scala.collection.mutable.HashMap[String, String] // name -> className
val annotations = new collection.mutable.HashMap[String, List[String]]

def generateSourceFile() {
import java.io._
val metaSrcDir = "src/main/scala/"+packageName+"/meta"
val metaSrcDir = "src/main/scala/" + packageName.replace('.', '/') + "/meta"
val dir = new File(metaSrcDir)
if( ! dir.exists ) dir.mkdir
val file = new FileWriter( metaSrcDir+"/"+modelName+"Meta.scala")
if (!dir.exists) dir.mkdirs
val file = new FileWriter(metaSrcDir + "/" + modelName + "Meta.scala")
file.write(contents)
file.close
}

private def contents:String = {
val valsSrc = props.keys.map( k => props(k) match {
private def attribute(prop: String, k: String): String = {
annotations.get(prop).flatMap {
_.find(_.startsWith("org.slim3.datastore.Attribute")).flatMap { a =>
System.out.println(a)
val re = """.*%s = ([^,]+).*\)""".format(k).r
a match {
case re(v) => Some(v.trim)
case _ => None
}
}
} getOrElse ""
}

private def contents: String = {
val collections = collection.mutable.Map[String, Pair[String, String]]()
val persistentProps = props.keys.filter { attribute(_, "persistent") != "false" }
val CollectionType = """java\.util\.(?:ArrayList|LinkedList|HashSet|LinkedHashSet|TreeSet|List|Set|SortedSet)\[(.+)\]""".r

val valsSrc = persistentProps.map(k => props(k) match {
case "String" =>
MetaTemplate.Attr.String.replace("$$propname$$",k)
val unindexed = if (attribute(k, "unindexed") == "true") "Unindexed" else ""
MetaTemplate.Attr.String.replace("$$propname$$", k).replace("$$unindexed$$", unindexed)
case "com.google.appengine.api.datastore.Key" =>
MetaTemplate.Attr.Key
case clazz @ CollectionType(t) =>
val unindexed = if (attribute(k, "unindexed") == "true") "Unindexed" else ""
collections += (k -> (clazz, t))
if (t == "String")
MetaTemplate.Attr.StringCollection.replace("$$propname$$", k).replace("$$typename$$", clazz).replace("$$unindexed$$", unindexed)
else
MetaTemplate.Attr.Collection.replace("$$propname$$", k).replace("$$typename$$", clazz).replace("$$typename2$$", t).replace("$$unindexed$$", unindexed)
case clazz =>
MetaTemplate.Attr.Core.replace("$$propname$$",k).replace("$$typename$$", clazz)
} )
val modelToEntitySrc = props.keys.map( k =>
( props(k) match {
val unindexed = if (attribute(k, "unindexed") == "true") "Unindexed" else ""
MetaTemplate.Attr.Core.replace("$$propname$$", k).replace("$$typename$$", clazz).replace("$$unindexed$$", unindexed)
})

var prePutSrc = ""
var staticSrc = ""
props.keys.foreach { k =>
val re = """classOf\[(.+)\]""".r
attribute(k, "listener") match {
case re(v) =>
if (prePutSrc == "") prePutSrc = MetaTemplate.PrePutHeader
prePutSrc += MetaTemplate.PrePut.replace("$$modelname$$", modelName).replace("$$propname$$", k).replace("$$getter$$", toGetter(k)).replace("$$setter$$", toSetter(k))
staticSrc += MetaTemplate.AttributeListener.replace("$$propname$$", k).replace("$$listener$$", v)
case e =>
println("no listener found: " + e)
}
}

val modelToEntitySrc = persistentProps.map(k =>
(props(k) match {
case "com.google.appengine.api.datastore.Text" | "com.google.appengine.api.datastore.Blob" =>
MetaTemplate.ModelToEntity.Unindexed
case _ => MetaTemplate.ModelToEntity.Indexed
}).replace("$$propname$$",k).replace("$$getter$$",toGetter(k))
)
case "String" if attribute(k, "lob") == "true" => MetaTemplate.ModelToEntity.LongText
case "Array[Byte]" if attribute(k, "lob") == "true" => MetaTemplate.ModelToEntity.Blob
case _ if attribute(k, "unindexed") == "true" => MetaTemplate.ModelToEntity.Unindexed
case _ => MetaTemplate.ModelToEntity.Indexed
}).replace("$$propname$$", k).replace("$$getter$$", toGetter(k)))

val entityToModelSrc = persistentProps.map { k =>
if (attribute(k, "lob") != "true")
MetaTemplate.EntityToModel.replace("$$propname$$", k).replace("$$setter$$", toSetter(k)).replace("$$typename$$", props(k))
else props(k) match {
case "String" => MetaTemplate.EntityToModelLongText.replace("$$propname$$", k).replace("$$setter$$", toSetter(k))
case "Array[Byte]" => MetaTemplate.EntityToModelBlob.replace("$$propname$$", k).replace("$$setter$$", toSetter(k))
case _ => MetaTemplate.EntityToModelLob.replace("$$propname$$", k).replace("$$setter$$", toSetter(k))
}
}

val modelToJsonSrc = props.keys.map { k =>
if (collections.contains(k))
MetaTemplate.ModelToJsonCollection.replace("$$propname$$", k).replace("$$getter$$", toGetter(k))
else props(k) match {
case "Array[Byte]" => MetaTemplate.ModelToJsonBlob.replace("$$propname$$", k).replace("$$getter$$", toGetter(k))
case _ => MetaTemplate.ModelToJson.replace("$$propname$$", k).replace("$$getter$$", toGetter(k))
}
}

val jsonToModelSrc = props.keys.map { k =>
if (collections.contains(k)) {
val (col, clz) = collections(k) match {
case (c, t) if c.startsWith("java.util.List") => ("java.util.ArrayList[%s]".format(t), t)
case (c, t) if c.startsWith("java.util.Set") => ("java.util.HashSet[%s]".format(t), t)
case (c, t) if c.startsWith("java.util.SortedSet") => ("java.util.TreeSet[%s]".format(t), t)
case e => e
}
MetaTemplate.JsonToModelCollection.replace("$$propname$$", k).replace("$$clazz$$", clz).replace("$$collection$$", col).replace("$$getter$$", toGetter(k)).replace("$$setter$$", toSetter(k))
} else props(k) match {
case "Array[Byte]" =>
MetaTemplate.JsonToModelBlob.replace("$$propname$$", k).replace("$$clazz$$", props(k)).replace("$$getter$$", toGetter(k)).replace("$$setter$$", toSetter(k))
case _ =>
MetaTemplate.JsonToModel.replace("$$propname$$", k).replace("$$clazz$$", props(k)).replace("$$getter$$", toGetter(k)).replace("$$setter$$", toSetter(k))
}
}

val entityToModelSrc = props.keys.map( k =>
MetaTemplate.EntityToModel.replace("$$propname$$",k).replace("$$setter$$",toSetter(k)).replace("$$typename$$", props(k))
)
MetaTemplate.MetaClass
.replace("$$instance_variables$$",valsSrc.mkString)
.replace("$$entity_to_model$$",entityToModelSrc.mkString)
.replace("$$model_to_entity$$",modelToEntitySrc.mkString)
.replace("$$modelname$$",modelName)
.replace("$$package$$",packageName)
.replace("$$instance_variables$$", valsSrc.mkString)
.replace("$$entity_to_model$$", entityToModelSrc.mkString)
.replace("$$model_to_entity$$", modelToEntitySrc.mkString)
.replace("$$model_to_json$$", modelToJsonSrc.mkString)
.replace("$$json_to_model$$", jsonToModelSrc.mkString)
.replace("$$pre_put$$", prePutSrc)
.replace("$$modelname$$", modelName)
.replace("$$package$$", packageName)
.replace("$$static$$", staticSrc)
}

private def toGetter(s:String) = "get" + toCamelCase(s)
private def toSetter(s:String) = "set" + toCamelCase(s)
private def toCamelCase(s:String) = s.substring(0, 1).toUpperCase() + s.substring(1)
private def toGetter(s: String) = "get" + toCamelCase(s)
private def toSetter(s: String) = "set" + toCamelCase(s)
private def toCamelCase(s: String) = s.substring(0, 1).toUpperCase() + s.substring(1)

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,115 @@ package scalatohoku.slim3
object MetaTemplate {
object Attr {
val String = """
val $$propname$$ = new StringAttributeMeta[$$modelname$$](this, "$$propname$$", "$$propname$$")"""
val $$propname$$ = new String$$unindexed$$AttributeMeta[$$modelname$$](this, "$$propname$$", "$$propname$$")"""
val Core = """
val $$propname$$ = new CoreAttributeMeta[$$modelname$$,$$typename$$](this, "$$propname$$", "$$propname$$",classOf[$$typename$$])"""
val $$propname$$ = new Core$$unindexed$$AttributeMeta[$$modelname$$,$$typename$$](this, "$$propname$$", "$$propname$$",classOf[$$typename$$])"""
val Key = """
val key = new CoreAttributeMeta[$$modelname$$,Key](this, "__key__", "key", classOf[Key])"""
val StringCollection = """
val $$propname$$ = new org.slim3.datastore.StringCollection$$unindexed$$AttributeMeta[$$modelname$$, $$typename$$](this, "$$propname$$", "$$propname$$", classOf[$$typename$$])"""
val Collection = """
val $$propname$$ = new org.slim3.datastore.Collection$$unindexed$$AttributeMeta[$$modelname$$, $$typename$$, $$typename2$$](this, "$$propname$$", "$$propname$$", classOf[$$typename$$])"""
}

val EntityToModel = """
model.$$setter$$(entity.getProperty("$$propname$$").asInstanceOf[$$typename$$])"""

val EntityToModelLob = """
val _$$propname$$ = blobToSerializable(entity.getProperty("$$propname$$").asInstanceOf[com.google.appengine.api.datastore.Blob])
model.$$setter$$(_$$propname$$)"""

val EntityToModelLongText = """
model.$$setter$$(textToString(entity.getProperty("$$propname$$").asInstanceOf[com.google.appengine.api.datastore.Text]))"""

val EntityToModelBlob = """
model.$$setter$$(blobToBytes(entity.getProperty("$$propname$$").asInstanceOf[com.google.appengine.api.datastore.Blob]))"""

object ModelToEntity {
val Indexed = """
entity.setProperty("$$propname$$", m.$$getter$$())"""
val Unindexed = """
entity.setUnindexedProperty("$$propname$$", m.$$getter$$())"""
val LongText = """
entity.setUnindexedProperty("$$propname$$", stringToText(m.$$getter$$()))"""
val Blob = """
entity.setUnindexedProperty("$$propname$$", bytesToBlob(m.$$getter$$()))"""
}

val ModelToJson = """
if(m.$$getter$$() != null){
writer.setNextPropertyName("$$propname$$")
encoder0.encode(writer, m.$$getter$$())
}
"""
val ModelToJsonCollection = """
if(m.$$getter$$() != null){
writer.setNextPropertyName("$$propname$$")
writer.beginArray()
m.$$getter$$.foreach{encoder0.encode(writer, _)}
writer.endArray()
}
"""
val ModelToJsonBlob = """
if(m.$$getter$$ != null){
writer.setNextPropertyName("$$propname$$")
encoder0.encode(writer, new com.google.appengine.api.datastore.ShortBlob(m.$$getter$$))
}
"""
val JsonToModel = """
reader = rootReader.newObjectReader("$$propname$$");
m.$$setter$$(decoder0.decode(reader, m.$$getter$$(), classOf[$$clazz$$]));
"""
val JsonToModelCollection = """
reader = rootReader.newObjectReader("$$propname$$");
{
val elements = new $$collection$$
val r = rootReader.newArrayReader("$$propname$$")
if(r != null){
reader = r
val n = r.length
(0 until r.length).foreach{i =>
r.setIndex(i)
val v = decoder0.decode(reader, null.asInstanceOf[$$clazz$$])
if(v != null){
elements.add(v)
}
}
m.$$setter$$(elements)
}
}
"""
val JsonToModelBlob = """
if(m.$$getter$$ != null){
m.$$setter$$(decoder0.decode(reader, new com.google.appengine.api.datastore.ShortBlob(m.$$getter$$)).getBytes)
} else {
val v = decoder0.decode(reader, null.asInstanceOf[com.google.appengine.api.datastore.ShortBlob])
if(v != null){
m.$$setter$$(v.getBytes)
} else {
m.$$setter$$(null)
}
}
"""

val AttributeListener = """
val slim3_$$propname$$AttributeListener = new $$listener$$
"""
val PrePutHeader = """
val m = model.asInstanceOf[$$modelname$$]
"""

val PrePut = """
m.$$setter$$($$modelname$$Meta.slim3_$$propname$$AttributeListener.prePut(m.$$getter$$()));
"""

val MetaClass = """// auto generated by ModelMetaGeneratorPlugin
package $$package$$.meta

import $$package$$.model.$$modelname$$
import org.slim3.datastore._
import com.google.appengine.api.datastore._
import collection.JavaConversions._

class $$modelname$$Meta extends ModelMeta[$$modelname$$]("$$modelname$$", classOf[$$modelname$$]) {

Expand Down Expand Up @@ -57,21 +144,42 @@ $$model_to_entity$$
override def getVersion(model:Any):Long = {
model.asInstanceOf[$$modelname$$].getVersion
}
override def assignKeyToModelRefIfNecessary(ds:com.google.appengine.api.datastore.AsyncDatastoreService, model:Any):Unit = {
}
override def incrementVersion(model:Any):Unit = {
val m = model.asInstanceOf[$$modelname$$]
val version = m.getVersion()
m.setVersion( version + 1 )
}
override def prePut(model:Any):Unit = {
assignKeyIfNecessary(model)
incrementVersion(model)
$$pre_put$$
}
override def postGet(model:Any):Unit = {
}
override def isCipherProperty(propertyName:String) = false

override def modelToJson(writer:org.slim3.datastore.json.JsonWriter, model:Any, maxDepth:Int, currentDepth:Int) {
val m = model.asInstanceOf[$$modelname$$]
writer.beginObject()
val encoder0 = new org.slim3.datastore.json.Default
$$model_to_json$$
writer.endObject()
}

override def jsonToModel(rootReader:org.slim3.datastore.json.JsonRootReader, maxDepth:Int, currentDepth:Int):$$modelname$$ = {
val m = new $$modelname$$
var reader:org.slim3.datastore.json.JsonReader = null
val decoder0:org.slim3.datastore.json.Default = new org.slim3.datastore.json.Default
$$json_to_model$$
m
}

override def getSchemaVersionName = "slim3.schemaVersion"
override def getClassHierarchyListName = "slim3.classHierarchyList";
}
object $$modelname$$Meta extends $$modelname$$Meta{
def get = this
$$static$$
}
"""
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class ModelMetaGeneratorPlugin(val global: Global) extends Plugin {
case prop @ ValDef(mods,name,tpt,rhs) if hasAnotation(prop,"scala.reflect.BeanProperty") =>
p( " <property>"+prop.name + ":" + prop.symbol.tpe.toLongString )
meta.props.put( prop.name.toString.trim, prop.symbol.tpe.toString )
meta.annotations.put(prop.name.toString.trim, prop.symbol.annotations.map(_.toString))
p(" <annotations>" + prop.symbol.annotations.map(_.toString()).mkString(","))
case method @ DefDef(mods,name,tparams,vparams,tpt,rhs) if isJavaAccessor(method) =>
()//p( " <accessor>"+method.name )
case _ => ()
Expand Down
20 changes: 20 additions & 0 deletions Slim3ModelTest/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
organization := "scalatohoku"

name := "Slim3ModelTest"

version := "0.1"

scalaVersion := "2.9.1"

autoCompilerPlugins := true

addCompilerPlugin("scalatohoku.slim3" %% "slim3modelmetageneratorplugin" % "0.1")

libraryDependencies ++= Seq(
"org.slim3" % "slim3" % "1.0.13"
)

resolvers ++= Seq(
"seasar" at "https://www.seasar.org/maven/maven2"
)

Binary file removed Slim3ModelTest/lib/appengine-api-1.0-sdk-1.3.5.jar
Binary file not shown.
Binary file removed Slim3ModelTest/lib/appengine-api-labs-1.3.5.jar
Binary file not shown.
Binary file removed Slim3ModelTest/lib/gwt-servlet.jar
Binary file not shown.
Binary file removed Slim3ModelTest/lib/junit-4.7.jar
Binary file not shown.
Binary file removed Slim3ModelTest/lib/ktrwjr.jar
Binary file not shown.
Binary file removed Slim3ModelTest/lib/slim3-1.0.5.jar
Binary file not shown.
Loading