From c34809c0ec2c9e99ed5d3d8e2cfce0d5c261dae3 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Fri, 30 Sep 2011 15:31:00 +0000 Subject: [PATCH] First version of XmlBuilder generator, only getters work right now --- .../java/com/google/gwt/query/Query.gwt.xml | 4 + .../com/google/gwt/query/client/GQuery.java | 4 +- .../builders/{JsonName.java => Name.java} | 4 +- .../gwt/query/client/builders/XmlBuilder.java | 38 ++++ .../query/client/builders/XmlBuilderBase.java | 89 ++++++++++ .../google/gwt/query/client/js/JsUtils.java | 17 ++ .../query/rebind/JsonBuilderGenerator.java | 4 +- .../gwt/query/rebind/XmlBuilderGenerator.java | 165 ++++++++++++++++++ .../gwt/query/client/GQueryAjaxTest.java | 37 +++- 9 files changed, 350 insertions(+), 12 deletions(-) rename gwtquery-core/src/main/java/com/google/gwt/query/client/builders/{JsonName.java => Name.java} (85%) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilder.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilderBase.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/XmlBuilderGenerator.java diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml index c8d1a594..61cdd0df 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -17,9 +17,13 @@ + + + + diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index 25d51e1f..f754f4ac 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -3763,12 +3763,12 @@ public class GQuery implements Lazy { } /** - * Return the text contained in the first matched element. + * Return the concatened text contained in the matched elements. */ public String text() { String result = ""; for (Element e : elements) { - result += e.getInnerText(); + result += JsUtils.text(e); } return result; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonName.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/Name.java similarity index 85% rename from gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonName.java rename to gwtquery-core/src/main/java/com/google/gwt/query/client/builders/Name.java index c3855793..5507677e 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonName.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/Name.java @@ -21,9 +21,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * Annotation used to specify the attribute, tag or property name + * in Json or Xml builders. */ @Target({METHOD}) @Retention(RetentionPolicy.RUNTIME) -public @interface JsonName { +public @interface Name { String value(); } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilder.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilder.java new file mode 100644 index 00000000..bf3153ed --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilder.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011, The gwtquery team. + * + * 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.google.gwt.query.client.builders; + +import com.google.gwt.dom.client.Element; + +/** + * Tagging interface used to generate XmlBuilder classes. + */ +public interface XmlBuilder { + /** + * load a string or a documentElement. + */ + J load(Object o); + + /** + * parses a xml string and loads the resulting documentElement. + */ + J parse(String xml); + + /** + * Returns the documentElement. + */ + Element getDocumentElement(); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilderBase.java new file mode 100644 index 00000000..0c7fe017 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/XmlBuilderBase.java @@ -0,0 +1,89 @@ +/* + * Copyright 2011, The gwtquery team. + * + * 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.google.gwt.query.client.builders; + +import static com.google.gwt.query.client.GQuery.$; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.GQuery; +import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.js.JsUtils; + +public abstract class XmlBuilderBase> implements XmlBuilder { + + //TODO empty document + protected GQuery g = $(JsUtils.parseXML("")); + + @SuppressWarnings("unchecked") + public J parse(String xml) { + return load(JsUtils.parseXML(xml)); + } + + @SuppressWarnings("unchecked") + public J load(Object o) { + assert o == null || o instanceof JavaScriptObject && JsUtils.isElement((JavaScriptObject)o) || o instanceof String; + if (o != null && o instanceof String) { + return parse((String)o); + } + if (o != null) { + g=$((Element)o); + } + return (J)this; + } + + public String getText() { + return g.text(); + } + + public void setText(String s) { + g.text(s); + } + + public String toString() { + return g.toString(); + } + + protected Element getElementBase(String n) { + return g.children(n).get(0); + } + + protected Element[] getElementsBase(String n) { + return g.children(n).elements(); + } + + public Element getDocumentElement() { + return g.get(0); + } + + protected float getFloatBase(String s) { + String n = getStrBase(s).replaceAll("[^\\d\\-\\.]", ""); + return n.isEmpty() ? 0 : Float.parseFloat(n); + } + + protected Boolean getBooleanBase(String n) { + return "true".equalsIgnoreCase(getStrBase(n)); + } + + protected String getStrBase(String n) { + return g.attr(n); + } + + protected Properties getPropertiesBase(String n) { + // TODO: + return null; + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index 307b7c5c..5d64a465 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -46,6 +46,10 @@ public class JsUtils { return (new XMLSerializer()).serializeToString(o); }-*/; + public String text(Element e) { + return e.getInnerText(); + } + public JsArray unique(JsArray a) { JsArray ret = JavaScriptObject.createArray().cast(); JsCache cache = JsCache.create(); @@ -93,6 +97,15 @@ public class JsUtils { } return super.unique(a); } + + @Override + public String text(Element e) { + return isXML(e) ? xmlText(e) : super.text(e); + } + + private native String xmlText(Element e) /*-{ + return e.text; + }-*/; } /** @@ -260,6 +273,10 @@ public class JsUtils { return utilsImpl.XML2String(o); } + public static String text(Element e) { + return utilsImpl.text(e); + } + /** * Parses a xml string and return the xml document element which * can then be passed to GQuery to create a typical GQuery object diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java index 35c6022f..76d5a76c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java @@ -31,7 +31,7 @@ import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.builders.JsonBuilder; -import com.google.gwt.query.client.builders.JsonName; +import com.google.gwt.query.client.builders.Name; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; @@ -81,7 +81,7 @@ public class JsonBuilderGenerator extends Generator { public void generateMethod(SourceWriter sw, JMethod method, TreeLogger logger) throws UnableToCompleteException { - JsonName nameAnnotation = method.getAnnotation(JsonName.class); + Name nameAnnotation = method.getAnnotation(Name.class); String name = nameAnnotation != null ? nameAnnotation.value() : method.getName().replaceFirst("^(get|set)", "").toLowerCase(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/XmlBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/XmlBuilderGenerator.java new file mode 100644 index 00000000..b0218d7f --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/XmlBuilderGenerator.java @@ -0,0 +1,165 @@ +/* + * Copyright 2011, The gwtquery team. + * + * 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.google.gwt.query.rebind; + +import java.io.PrintWriter; + +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JArrayType; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JParameter; +import com.google.gwt.core.ext.typeinfo.JPrimitiveType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.builders.XmlBuilder; +import com.google.gwt.query.client.builders.Name; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; + +/** + */ +public class XmlBuilderGenerator extends Generator { + TypeOracle oracle; + static JClassType xmlBuilderType; + static JClassType stringType; + + public String generate(TreeLogger treeLogger, + GeneratorContext generatorContext, String requestedClass) + throws UnableToCompleteException { + oracle = generatorContext.getTypeOracle(); + JClassType clazz = oracle.findType(requestedClass); + xmlBuilderType = oracle.findType(XmlBuilder.class.getName()); + stringType = oracle.findType(String.class.getName()); + + String t[] = generateClassName(clazz); + + SourceWriter sw = getSourceWriter(treeLogger, generatorContext, t[0], + t[1], requestedClass); + if (sw != null) { + for (JMethod method : clazz.getMethods()) { + generateMethod(sw, method, treeLogger); + } + sw.commit(treeLogger); + } + return t[2]; + } + + public String[] generateClassName(JType t) { + String[] ret = new String[3]; + JClassType c = t.isClassOrInterface(); + ret[0] = c.getPackage().getName(); + ret[1] = c.getName().replace('.', '_') + "_XmlBuilder"; + ret[2] = ret[0] + "." + ret[1]; + return ret; + } + + public boolean isTypeAssignableTo(JType t, JClassType o) { + JClassType c = t.isClassOrInterface(); + return (c != null && c.isAssignableTo(o)); + } + + public void generateMethod(SourceWriter sw, JMethod method, TreeLogger logger) + throws UnableToCompleteException { + Name nameAnnotation = method.getAnnotation(Name.class); + String name = nameAnnotation != null ? nameAnnotation.value() + : method.getName().replaceFirst("^(get|set)", "").toLowerCase(); + + String retType = method.getReturnType().getParameterizedQualifiedSourceName(); + + sw.print("public final " + retType + " " + method.getName()); + JParameter[] params = method.getParameters(); + if (params.length == 0) { + JArrayType arr = method.getReturnType().isArray(); + sw.println("() {"); + sw.indent(); + if (retType.matches("(java.lang.Boolean|boolean)")) { + sw.println("return getBooleanBase(\"" + name + "\");"); + } else if (method.getReturnType().isPrimitive() != null) { + sw.println("return (" + retType + ")getFloatBase(\"" + name + "\");"); + } else if (isTypeAssignableTo(method.getReturnType(), stringType)) { + sw.println("return getStrBase(\"" + name + "\");"); + } else if (isTypeAssignableTo(method.getReturnType(), xmlBuilderType)) { + String q = method.getReturnType().getQualifiedSourceName(); + sw.println("Element e = getElementBase(\"" + name + "\");"); + sw.println("return e == null ? null : (" + q + ")((" + q + ")GWT.create(" + q + ".class)).load(e);"); + } else if (retType.equals(Properties.class.getName())){ + sw.println("return getPropertiesBase(\"" + name + "\");"); + } else if (arr != null) { + String q = arr.getComponentType().getQualifiedSourceName(); + sw.println("ArrayList<" + q + "> l = new ArrayList<" + q+ ">();"); + sw.println("for (Element e: getElementsBase(\"" + name + "\")) {"); + sw.println(" " + q + " c = GWT.create(" + q + ".class);"); + sw.println(" c.load(e);"); + sw.println(" l.add(c);"); + sw.println("}"); + sw.println("return l.toArray(new " + q + "[0]);"); +// } else { +// sw.println("return p.get(\"" + name + "\");"); + } + sw.outdent(); + sw.println("}"); + } else if (params.length == 1) { + JType type = params[0].getType(); + JArrayType arr = type.isArray(); + JPrimitiveType pri = type.isPrimitive(); + sw.print("(" + type.getParameterizedQualifiedSourceName() + " a)"); + sw.println("{"); + sw.indent(); + if (arr != null) { + sw.println("setArrayBase(\"" + name + "\", a);"); + } else if (pri != null) { + } else { + sw.println("p.set(\"" + name + "\", a);"); + } + if (!"void".equals(retType)){ + if (isTypeAssignableTo(method.getReturnType(), method.getEnclosingType())) { + sw.println("return this;"); + } else { + sw.println("return null;"); + } + } + sw.outdent(); + sw.println("}"); + } + } + + protected SourceWriter getSourceWriter(TreeLogger logger, + GeneratorContext context, String packageName, String className, + String... interfaceNames) { + PrintWriter printWriter = context.tryCreate(logger, packageName, className); + if (printWriter == null) { + return null; + } + ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( + packageName, className); + composerFactory.setSuperclass("com.google.gwt.query.client.builders.XmlBuilderBase<" + + packageName + "." + className + ">"); + composerFactory.addImport("com.google.gwt.query.client.js.*"); + composerFactory.addImport("com.google.gwt.query.client.*"); + composerFactory.addImport("com.google.gwt.core.client.*"); + composerFactory.addImport("com.google.gwt.dom.client.*"); + composerFactory.addImport("java.util.*"); + for (String interfaceName : interfaceNames) { + composerFactory.addImplementedInterface(interfaceName); + } + return composerFactory.createSourceWriter(context, printWriter); + } +} diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTest.java index 540e1b41..841015b4 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTest.java @@ -20,7 +20,8 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.query.client.builders.JsonBuilder; -import com.google.gwt.query.client.builders.JsonName; +import com.google.gwt.query.client.builders.Name; +import com.google.gwt.query.client.builders.XmlBuilder; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; @@ -48,21 +49,21 @@ public class GQueryAjaxTest extends GWTTestCase { } } - interface MyClass extends JsonBuilder { + interface JsonExample extends JsonBuilder { int getA(); - MyClass getB(); - @JsonName("u") + JsonExample getB(); + @Name("u") String getUrl(); long getD(); Boolean getZ(); String[] getT(); - MyClass setT(String[] strings); - MyClass setZ(Boolean b); + JsonExample setT(String[] strings); + JsonExample setZ(Boolean b); } public void testJsonBuilder() { String json = "[{a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true}]"; - MyClass c = GWT.create(MyClass.class); + JsonExample c = GWT.create(JsonExample.class); assertEquals(0, c.getA()); c.parse(json, true); assertEquals(1, c.getA()); @@ -79,4 +80,26 @@ public class GQueryAjaxTest extends GWTTestCase { assertEquals("foo", c.getT()[0]); assertEquals("bar", c.getT()[1]); } + + interface XmlExample extends XmlBuilder { + String getA(); + Boolean getB(); + @Name("c") + int getNumber(); + + XmlExample[] getX(); + @Name("x") + XmlExample getFirstX(); + } + + public void testXmlBuilder() { + String xml = " text"; + XmlExample x = GWT.create(XmlExample.class); + x.parse(xml); + assertTrue(x.getB()); + assertEquals("ra", x.getA()); + assertEquals(-1, x.getNumber()); + assertEquals("xa2", x.getX()[1].getA()); + assertEquals("xa1", x.getFirstX().getA()); + } } -- 2.39.5