Esses dias eu estava brincando com uma aplicação e me entendiou o fato de ter que ficar duplicando as classes VO do Java para o Flex na mão. Comecei a pesquisar e vi a solução GAS do Granite. Contudo achei a geração das classes em ActionScript muito verbosa. Eu queria algo mais simples, que o nome da classe, o alias, e os atributos fossem copiados. Acabei não encontrando algo simples assim, aí acabei fazendo uma solução caseira rapidamente usando o próprio Flex. Não me importei com testes unitários, mas o fato é que a aplicação funcionou bem para as classes que eu estava fazendo. Para usar, basta colar o código da classe Java no Browser. Estou postando também o código fonte, apesar de ele ser bem porquinho J, para quem kiser adaptar a solução para seus propósitos.
public class J2ASConverter {
public function convertToAS(javaClass:String):String {
var str:String='[RemoteClass(alias="';
str+=buildAlias(javaClass)+'")]';
str+="\npublic class "+getClassName(javaClass)+"{";
str+=buildFields(javaClass);
return str+"\n}";
}
private function buildFields(javaClass:String):String {
var fieldsAS:String="";
for each(var field:Object in getFields(javaClass)) {
fieldsAS+="\n\tpublic var "+field.fieldName+":"+field.fieldType+";";
}
return fieldsAS;
}
private function getFields(javaClass:String):Array {
var classSearchIndex:int=javaClass.indexOf("class");
if(classSearchIndex>=0) {
do {
++classSearchIndex;
} while(classSearchIndex "{");
++classSearchIndex;
var fields:Array=[];
var abreChave:int=0;
while(classSearchIndex
if(abreChave==0) {
var line:String="";
while(classSearchIndex ";") {
line+=javaClass.charAt(classSearchIndex);
++classSearchIndex;
}
line=removePossibleJavaAnnotations(line);
if(isField(line)) {
if(line.indexOf("}")==-1) {
fields.push(extractTypeAndName(line));
}
} else {
++abreChave;
}
} else if(javaClass.charAt(classSearchIndex)=="}") {
--abreChave;
} else if(javaClass.charAt(classSearchIndex)=="{") {
++abreChave;
}
++classSearchIndex;
}
return fields;
}
return [];
}
private function removePossibleJavaAnnotations(line:String):String {
var searchIndex:int=line.indexOf("@");
if(searchIndex!=-1) {
++searchIndex;
while(searchIndex "(") {
++searchIndex;
}
var parentesiNumber:int=1;
++searchIndex;
while(searchIndex
if(line.charAt(searchIndex)=="(") {
++parentesiNumber;
} else if(line.charAt(searchIndex)==")") {
--parentesiNumber;
}
++searchIndex;
}
if(searchIndex
return line.substring(++searchIndex);
}
return line;
}
private function extractTypeAndName(line:String):Object {
line=line.split("=")[0];
var searchIndex:int=line.length-1;
while(searchIndex!=-1&&line.charAt(searchIndex)==" ") {
--searchIndex;
}
var javaFieldName:String="";
while(searchIndex!=-1&&line.charAt(searchIndex)!=" ") {
javaFieldName=line.charAt(searchIndex)+javaFieldName;
--searchIndex;
}
while(searchIndex!=-1&&line.charAt(searchIndex)==" ") {
--searchIndex;
}
var javaFieldType:String="";
while(searchIndex!=-1&&line.charAt(searchIndex)!=" ") {
javaFieldType=line.charAt(searchIndex)+javaFieldType;
--searchIndex;
}
return { fieldType:java2ASType(javaFieldType),fieldName:javaFieldName };
}
private function java2ASType(javaType:String):String {
javaType=javaType.replace("<.*>","");
javaType=javaType.replace(" ","");
if(javaType=="Set"||javaType=="List") {
return "ArrayCollection";
} else if(javaType=="int"||javaType=="Integer"||javaType=="short"||javaType=="Short"||javaType=="long"||javaType=="Long"||javaType=="float"||javaType=="Float"||javaType=="double"||javaType=="Double") {
return "Number";
} else if(javaType=="Calendar") {
return "Date";
}
return "Date";
}
return javaType;
}
private function isField(line:String):Boolean {
var firstLinePart:String=line.split("=")[0];
return firstLinePart.indexOf("{")==-1;
}
private function buildAlias(javaClass:String):String {
var packageIndex:int=javaClass.indexOf("package");
var packageNameBegin:int=0;
var alias:String="";
if(packageIndex>=0) {
for(packageNameBegin=packageIndex+7;javaClass.charAt(packageNameBegin)==" ";++packageNameBegin) {
}
if(javaClass.indexOf(";")>packageNameBegin) {
var char:String=javaClass.charAt(packageNameBegin);
while(char!=";") {
alias+=char;
char=javaClass.charAt(++packageNameBegin);
}
alias+="."+getClassName(javaClass);
}
}
return alias;
}
private function getClassName(javaClass:String):String {
var classWordIndex:int=javaClass.indexOf("class");
if(classWordIndex>=0) {
classWordIndex+=5;
while(javaClass.charAt(classWordIndex)==" ") {
++classWordIndex;
}
var className:String="";
do {
className+=javaClass.charAt(classWordIndex);
++classWordIndex;
} while(classWordIndex " "&&javaClass.charAt(classWordIndex)!="{");
return className;
}
return "";
}
}
Se a classe completa do Java for utilizada, incluindo a linha com o package, a mini-aplicação monta o metadado RemoteClass com o respectivo alias.
Espero que a aplicação ajude mais alguém.