Metadataを活用し、動的にDtoを作る

JavascriptからDataを取得する場合、Entityの一部のみで良い場合が良くあります。
その度に、Dtoを作るのが面倒ですので、slim3のMetadataを使用して、作るRoutineを書いてみました。
使用方法は、

  private LginMeta m = LginMeta.get();
  DtoAdhoc da = DatastoreUtil.dto().add(m.logi, m.name, m.sec);
  HashMap hm = da.toMapWithKeyJSON(res);

  //尚一回だけの使用であれば下記の様に勿論書けます。流れるインターフェースは良いですね。
  HashMap hm = DatastoreUtil.dto().add(m.logi, m.name, m.sec).toMapWithKeyJSON(res);

ソースは下記の様に簡単です。

public class DatastoreUtil {
	public static DtoAdhoc dto() {
		return new DtoAdhoc();
	}
}

public class DtoAdhoc {

	private ArrayList fields = new ArrayList();
	private BeanDesc beanDesc;
	public DtoAdhoc add(CoreAttributeMeta... flds) {
		for (CoreAttributeMeta fld : flds) {
			fields.add(fld.getName());
		}
		return this;
	}
	public HashMap toMap(Object o) {
		HashMap res = new HashMap();

		for (String fld : fields) {
			res.put(fld, getBeanDesc(o).getPropertyDesc(fld).getValue(o));
		}

		return res;
	}
	public HashMap toMapWithKeyJSON(Object o) {
		HashMap res = toMap(o);
		res.put("key", JSON.encode(getBeanDesc(o).getPropertyDesc("key")
				.getValue(o)));
		return res;
	}
	protected BeanDesc getBeanDesc(Object o) {
		if (beanDesc != null) {
			return beanDesc;
		}
		beanDesc = BeanUtil.getBeanDesc(o.getClass());
		return beanDesc;
	}
}

GAE/J JDO Query Eclipse Plugin

やっぱり手作業で Entity ClassにConstantを作るのは面倒なので、Eclipse Pluginを作りました。

はじめての Pluginでしたが、竹添さんの本と Google先生の助けで、意外と簡単にできました。

Mainの部分は以下の通りです。

public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil
.getActiveWorkbenchWindowChecked(event);
IEditorPart editorPart = window.getActivePage().getActiveEditor();
IEditorInput editorInput = editorPart.getEditorInput();
ICompilationUnit iCompilationUnit = (ICompilationUnit) editorInput
.getAdapter(IJavaElement.class);

try {
IType itypes = iCompilationUnit.getAllTypes();
if (itypes.length ==1){
IType it = itypes[0];
IField
fields=it.getFields();
for (IField iField : fields) {
IAnnotation annos = iField.getAnnotations();
for (IAnnotation iAnnotation : annos) {
if (iAnnotation.getElementName().equals("Persistent")){
checkAndCreateClassField(iField.getElementName(),fields,it);

}

}

}
}
} catch (JavaModelException e) {
e.printStackTrace();
}

MessageDialog.openInformation(window.getShell(), "Generete Datastore Constant",

"Constant Generated");
return null;
}

private void checkAndCreateClassField(String elementName, IField fields,
IType itype) {
for (IField field : fields) {
if (field.getElementName().equals("C_"+elementName)){
return;
}
}
try {
itype.createField("static public final String C_"+elementName+" = \""+elementName+"\" ;", null, true, new NullProgressMonitor());
} catch (JavaModelException e) {
e.printStackTrace();
}
}

GAE/J JDO Query 流れるインターフェース Typesafe

GAE/Jの場合、結合はすべて ANDなので、Filterの自動作成がやり易い。

下記 Utilityを作成した。

これを使うと、

query.setFilter( ( new QueryFilter( ) ).sEq("delete", "N").toString());

と書ける。(勿論流れる インターフェスなので複数連続できる)

このままでは typesafeにならないし、あえてMETA Classに定義するのは
面倒なので、entity Classに下記定義を行う。

static public final String C_delete = "delete";

これにより、上記は、次の様に書ける。

query.setFilter ( ( new QueryFilter( )).sEq(Table.C_delete, "N").toString());


これも、いちいち手作業で間違えたら元も子もないし、EclipseのPluginを作る
程でもないので、下記 GenerateEntityConstant Classを作ったので、

mainから呼び出して、ConsoleにPrintして コピペで OK.

これで使い易くなった。

public class QueryFilter {
private StringBuffer fstring = new StringBuffer();

public QueryFilter eq(String element, Object value) {
checkAnd();
fstring.append(element +" == "+value);
return this;
}

public QueryFilter sEq(String element, String value) {
checkAnd();
fstring.append(element +" == '"+value+"'");
return this;
}

public QueryFilter ge(String element, Object value) {
checkAnd();
fstring.append(element +" >= "+value);
return this;
}

public QueryFilter sGe(String element, String value) {
checkAnd();
fstring.append(element +" >= '"+value+"'");
return this;
}

public QueryFilter gr(String element, Object value) {
checkAnd();
fstring.append(element +" > "+value);
return this;
}

public QueryFilter sGr(String element, String value) {
checkAnd();
fstring.append(element +" > '"+value+"'");
return this;
}
public QueryFilter le(String element, Object value) {
checkAnd();
fstring.append(element +" <= "+value);
return this;
}

public QueryFilter sLe(String element, String value) {
checkAnd();
fstring.append(element +" <= '"+value+"'");
return this;
}

public QueryFilter between(String element, Object from, Object to) {
checkAnd();
fstring.append(element +" >= "+from + " && "+element + " <= " +to);
return this;
}

public QueryFilter sBetween(String element, Object from, Object to) {
checkAnd();
fstring.append(element +" >= '"+from + "' && "+element + " <= '" +to+"'");
return this;
}

public QueryFilter lt(String element, Object value) {
checkAnd();
fstring.append(element +" < "+value);
return this;
}

public QueryFilter sLt(String element, String value) {
checkAnd();
fstring.append(element +" < '"+value+"'");
return this;
}

public QueryFilter startWith(String element, String value) {
checkAnd();
char c = 255;
fstring.append(element +" >= '"+value+"' && "+element +" <= '"+value+Character.toString(c)+"'");
return this;
}

public String toString(){
return fstring.toString();
}
private void checkAnd() {
if (fstring.length() > 0) {
fstring.append(" && ");
}
}

}

public static void main(String[] args) {
System.out.print(GenerateEntityConstant.getGenerateProgram(Table.class));

}

public class GenerateEntityConstant {

static public String getGenerateProgram(Class clazz){
StringBuffer sb = new StringBuffer();
try {
BeanInfo info = Introspector.getBeanInfo(clazz, Object.class);
PropertyDescriptor[] pds= info.getPropertyDescriptors();
for (PropertyDescriptor pdone : pds) {
String name = pdone.getName();
sb.append("static public final String C_"+name+" = \""+name+"\";\n");
}
} catch (IntrospectionException e) {

e.printStackTrace();
}
return sb.toString();
}

}

GAE/J VersionStrategy.VERSION_NUMBER

GAE/J で Versionを使って Controlすると、自動的に「OPT_VERSION」
という Columnが Generateされて使われる。

これを、DTOに詰めて Clientにわたすには、Integer で OPT_VERSIONのFieldを
作ったら、上手くいった。


GAE/Jはまだなかなか情報が無くて、手探りですね。

SmartClient AJAX + GAE/J+GOOGLE APPS

EXT-JSは LicenseがLGPLでなくなって、使用に制約が多く、YUIもやってみましたが、機能が今一でした。

SmartClientの 7.0 RCが出たというので、使ってみましたら、Conceptとしては、EXT−JSに非常に近く、機能 特に Table関連やDynamic Form関連が大変使いやすそうです。

GAE/JのFront Endに使って見ます。


GOOGLE APPS

先日 まさたかさんのはてなで、GAEのPresentationがあるとの事で、サイオスGOOGLE APPSセミナーに行ってきました。

APPSのStandard Versionは無償で50人まで管理出来る事がわかったので早速やってみました。

申し込みと同時に Domainを取得すると、Google Apps経由ですべて作業が完了でき、費用も年$10でした。

登録直後は、AppsのDashboardに自分のDomainが表示されるものの、設定が出来ない状態でしたので、Google Check経由で問い合わせをしていましたら、2日弱で正常に接続できました。

AppsのDomainで GAEのサイトも接続できるので、大変お勧めです。

GAE/J 日本語文字化け Patch

下記 URLにある C#のPatch JAVAC.EXEを作ったら、とりあえず文字化けなしに
Upload可能となりました。

http://groups.google.com/group/google-appengine-java/browse_thread/thread/1345bf330766d8be

That's great!
And I have an alternative way to fix this problem.

I wrote a simple tool to add the encoding argument to javac.exe.

Just rename javac.exe to javac1.exe, and rename the tool to javac.exe.

Here is the main part of the tool (wrote in C#):

static int Main(string[] args)
{
string arg = "";

var cmd = Environment.CommandLine;
arg = cmd.Substring(cmd.IndexOf(args[0]));

if (!arg.Contains(" -encoding"))
arg += " -encoding UTF8";
Console.WriteLine("argment:{0}", arg);

Process p = new Process();
p.StartInfo.FileName = "javac1.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.Arguments = arg;

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = false;
p.Start();

while (true)
{
var msgStd = p.StandardOutput.ReadLine();
if (msgStd != null)
Console.WriteLine(msgStd);
var msgErr = p.StandardError.ReadLine();
if (msgErr != null)
Console.WriteLine(msgErr);

if (msgStd == null && msgErr == null)
break;
}

return p.ExitCode;
}