Generating skeleton for union classes that compiles OK union
authorJaroslav Tulach <jaroslav.tulach@netbeans.org>
Fri, 24 Jan 2014 13:15:30 +0100
branchunion
changeset 49073150bbfbf61
parent 483 c52158f52e8c
child 491 e24032333156
Generating skeleton for union classes that compiles OK
json/src/main/java/net/java/html/json/Model.java
json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
json/src/test/java/org/netbeans/html/json/impl/PlainEnumTest.java
     1.1 --- a/json/src/main/java/net/java/html/json/Model.java	Fri Jan 24 05:24:42 2014 +0100
     1.2 +++ b/json/src/main/java/net/java/html/json/Model.java	Fri Jan 24 13:15:30 2014 +0100
     1.3 @@ -129,7 +129,7 @@
     1.4   * @author Jaroslav Tulach <jtulach@netbeans.org>
     1.5   */
     1.6  @Retention(RetentionPolicy.SOURCE)
     1.7 -@Target(ElementType.TYPE)
     1.8 +@Target({ ElementType.TYPE, ElementType.FIELD })
     1.9  public @interface Model {
    1.10      /** Name of the model class */
    1.11      String className();
     2.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java	Fri Jan 24 05:24:42 2014 +0100
     2.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java	Fri Jan 24 13:15:30 2014 +0100
     2.3 @@ -123,13 +123,27 @@
     2.4      public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
     2.5          boolean ok = true;
     2.6          for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
     2.7 -            if (!processModel(e)) {
     2.8 +            if (e.getKind().isField()) {
     2.9 +                if (e.getKind() != ElementKind.ENUM_CONSTANT) {
    2.10 +                    error("Only enum constants fields can be annotated by @Model annotations", e);
    2.11 +                    ok = false;
    2.12 +                    continue;
    2.13 +                }
    2.14 +                if (e.getEnclosingElement().getAnnotation(Model.class) == null) {
    2.15 +                    error("Enclosing enum has to be annotated by @Model annotation", e);
    2.16 +                    ok = false;
    2.17 +                    continue;
    2.18 +                }
    2.19 +            } else if (!processModelOrEnum(e)) {
    2.20                  ok = false;
    2.21              }
    2.22          }
    2.23          if (roundEnv.processingOver()) {
    2.24              models.clear();
    2.25              for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
    2.26 +                if (!(entry.getKey() instanceof TypeElement)) {
    2.27 +                    continue;
    2.28 +                }
    2.29                  TypeElement te = (TypeElement)entry.getKey();
    2.30                  String fqn = processingEnv.getElementUtils().getBinaryName(te).toString();
    2.31                  Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
    2.32 @@ -171,6 +185,13 @@
    2.33          processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
    2.34      }
    2.35      
    2.36 +    private boolean processModelOrEnum(Element e) {
    2.37 +        if (e.getKind() == ElementKind.ENUM) {
    2.38 +            return processEnum(e);
    2.39 +        } else {
    2.40 +            return processModel(e);
    2.41 +        }
    2.42 +    }
    2.43      private boolean processModel(Element e) {
    2.44          boolean ok = true;
    2.45          Model m = e.getAnnotation(Model.class);
    2.46 @@ -213,6 +234,342 @@
    2.47              try {
    2.48                  w.append("package " + pkg + ";\n");
    2.49                  w.append("import net.java.html.json.*;\n");
    2.50 +                w.append("public final ");
    2.51 +                generateClassBody(w, className, body, e, props, functionDeps, propsDeps, propsGetSet, functions, onReceiveType);
    2.52 +            } finally {
    2.53 +                w.close();
    2.54 +            }
    2.55 +        } catch (IOException ex) {
    2.56 +            error("Can't create " + className + ".java", e);
    2.57 +            return false;
    2.58 +        }
    2.59 +        return ok;
    2.60 +    }
    2.61 +
    2.62 +    private void generateClassBody(Writer w, String className, StringWriter body, Element e, Prprt[] props, Map<String, Collection<String>> functionDeps, Map<String, Collection<String>> propsDeps, List<String> propsGetSet, List<String> functions, StringBuilder onReceiveType) throws IOException {
    2.63 +        w.append("class ").append(className).append(" implements Cloneable {\n");
    2.64 +        w.append("  private static final Html4JavaType TYPE = new Html4JavaType();\n");
    2.65 +        w.append("  private final org.apidesign.html.json.spi.Proto proto;\n");
    2.66 +        w.append(body.toString());
    2.67 +        w.append("  private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
    2.68 +        w.append("  private ").append(className).append("(net.java.html.BrwsrCtx context) {\n");
    2.69 +        w.append("    this.proto = TYPE.createProto(this, context);\n");
    2.70 +        for (Prprt p : props) {
    2.71 +            if (p.array()) {
    2.72 +                final String tn = typeName(e, p);
    2.73 +                String[] gs = toGetSet(p.name(), tn, p.array());
    2.74 +                w.write("    this.prop_" + p.name() + " = proto.createList(\""
    2.75 +                    + p.name() + "\"");
    2.76 +                if (functionDeps.containsKey(p.name())) {
    2.77 +                    int index = Arrays.asList(functionDeps.keySet().toArray()).indexOf(p.name());
    2.78 +                    w.write(", " + index);
    2.79 +                } else {
    2.80 +                    w.write(", -1");
    2.81 +                }
    2.82 +                Collection<String> dependants = propsDeps.get(p.name());
    2.83 +                if (dependants != null) {
    2.84 +                    for (String depProp : dependants) {
    2.85 +                        w.write(", ");
    2.86 +                        w.write('\"');
    2.87 +                        w.write(depProp);
    2.88 +                        w.write('\"');
    2.89 +                    }
    2.90 +                }
    2.91 +                w.write(")");
    2.92 +                w.write(";\n");
    2.93 +            }
    2.94 +        }
    2.95 +        w.append("  };\n");
    2.96 +        w.append("  public ").append(className).append("() {\n");
    2.97 +        w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
    2.98 +        for (Prprt p : props) {
    2.99 +            if (!p.array()) {
   2.100 +                boolean[] isModel = {false};
   2.101 +                boolean[] isEnum = {false};
   2.102 +                boolean isPrimitive[] = {false};
   2.103 +                String tn = checkType(p, isModel, isEnum, isPrimitive);
   2.104 +                if (isModel[0]) {
   2.105 +                    w.write("    prop_" + p.name() + " = new " + tn + "();\n");
   2.106 +                }
   2.107 +            }
   2.108 +        }
   2.109 +        w.append("  };\n");
   2.110 +        if (props.length > 0) {
   2.111 +            w.append("  public ").append(className).append("(");
   2.112 +            Prprt firstArray = null;
   2.113 +            String sep = "";
   2.114 +            for (Prprt p : props) {
   2.115 +                if (p.array()) {
   2.116 +                    if (firstArray == null) {
   2.117 +                        firstArray = p;
   2.118 +                    }
   2.119 +                    continue;
   2.120 +                }
   2.121 +                String tn = typeName(e, p);
   2.122 +                w.write(sep);
   2.123 +                w.write(tn);
   2.124 +                w.write(" " + p.name());
   2.125 +                sep = ", ";
   2.126 +            }
   2.127 +            if (firstArray != null) {
   2.128 +                String tn;
   2.129 +                boolean[] isModel = {false};
   2.130 +                boolean[] isEnum = {false};
   2.131 +                boolean isPrimitive[] = {false};
   2.132 +                tn = checkType(firstArray, isModel, isEnum, isPrimitive);
   2.133 +                w.write(sep);
   2.134 +                w.write(tn);
   2.135 +                w.write("... " + firstArray.name());
   2.136 +            }
   2.137 +            w.append(") {\n");
   2.138 +            w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
   2.139 +            for (Prprt p : props) {
   2.140 +                if (p.array()) {
   2.141 +                    continue;
   2.142 +                }
   2.143 +                w.write("    this.prop_" + p.name() + " = " + p.name() + ";\n");
   2.144 +            }
   2.145 +            if (firstArray != null) {
   2.146 +                w.write("    proto.initTo(this.prop_" + firstArray.name() + ", " + firstArray.name() + ");\n");
   2.147 +            }
   2.148 +            w.append("  };\n");
   2.149 +        }
   2.150 +        w.append("  private static class Html4JavaType extends org.apidesign.html.json.spi.Proto.Type<").append(className).append("> {\n");
   2.151 +        w.append("    private Html4JavaType() {\n      super(").append(className).append(".class, ").
   2.152 +            append(inPckName(e)).append(".class, " + (propsGetSet.size() / 5) + ", "
   2.153 +                + (functions.size() / 2) + ");\n");
   2.154 +        {
   2.155 +            for (int i = 0; i < propsGetSet.size(); i += 5) {
   2.156 +                w.append("      registerProperty(\"").append(propsGetSet.get(i)).append("\", ");
   2.157 +                w.append((i / 5) + ", " + (propsGetSet.get(i + 2) == null) + ");\n");
   2.158 +            }
   2.159 +        }
   2.160 +        {
   2.161 +            for (int i = 0; i < functions.size(); i += 2) {
   2.162 +                w.append("      registerFunction(\"").append(functions.get(i)).append("\", ");
   2.163 +                w.append((i / 2) + ");\n");
   2.164 +            }
   2.165 +        }
   2.166 +        w.append("    }\n");
   2.167 +        w.append("    @Override public void setValue(" + className + " data, int type, Object value) {\n");
   2.168 +        w.append("      switch (type) {\n");
   2.169 +        for (int i = 0; i < propsGetSet.size(); i += 5) {
   2.170 +            final String set = propsGetSet.get(i + 2);
   2.171 +            String tn = propsGetSet.get(i + 4);
   2.172 +            String btn = findBoxedType(tn);
   2.173 +            if (btn != null) {
   2.174 +                tn = btn;
   2.175 +            }
   2.176 +            if (set != null) {
   2.177 +                w.append("        case " + (i / 5) + ": data." + strip(set) + "(TYPE.extractValue(" + tn + ".class, value)); return;\n");
   2.178 +            }
   2.179 +        }
   2.180 +        w.append("      }\n");
   2.181 +        w.append("    }\n");
   2.182 +        w.append("    @Override public Object getValue(" + className + " data, int type) {\n");
   2.183 +        w.append("      switch (type) {\n");
   2.184 +        for (int i = 0; i < propsGetSet.size(); i += 5) {
   2.185 +            final String get = propsGetSet.get(i + 1);
   2.186 +            if (get != null) {
   2.187 +                w.append("        case " + (i / 5) + ": return data." + strip(get) + "();\n");
   2.188 +            }
   2.189 +        }
   2.190 +        w.append("      }\n");
   2.191 +        w.append("      throw new UnsupportedOperationException();\n");
   2.192 +        w.append("    }\n");
   2.193 +        w.append("    @Override public void call(" + className + " model, int type, Object data, Object ev) {\n");
   2.194 +        w.append("      switch (type) {\n");
   2.195 +        for (int i = 0; i < functions.size(); i += 2) {
   2.196 +            final String name = functions.get(i);
   2.197 +            w.append("        case " + (i / 2) + ": model." + name + "(data, ev); return;\n");
   2.198 +        }
   2.199 +        w.append("      }\n");
   2.200 +        w.append("      throw new UnsupportedOperationException();\n");
   2.201 +        w.append("    }\n");
   2.202 +        w.append("    @Override public org.apidesign.html.json.spi.Proto protoFor(Object obj) {\n");
   2.203 +        w.append("      return ((" + className + ")obj).proto;");
   2.204 +        w.append("    }\n");
   2.205 +        w.append("    @Override public void onChange(" + className + " model, int type) {\n");
   2.206 +        w.append("      switch (type) {\n");
   2.207 +        {
   2.208 +            String[] arr = functionDeps.keySet().toArray(new String[0]);
   2.209 +            for (int i = 0; i < arr.length; i++) {
   2.210 +                Collection<String> onChange = functionDeps.get(arr[i]);
   2.211 +                if (onChange != null) {
   2.212 +                    w.append("      case " + i + ":\n");
   2.213 +                    for (String call : onChange) {
   2.214 +                        w.append("      ").append(call).append("\n");
   2.215 +                    }
   2.216 +                    w.write("      return;\n");
   2.217 +                }
   2.218 +            }
   2.219 +        }
   2.220 +        w.append("    }\n");
   2.221 +        w.append("      throw new UnsupportedOperationException();\n");
   2.222 +        w.append("    }\n");
   2.223 +        w.append(onReceiveType);
   2.224 +        w.append("    @Override public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n");
   2.225 +        w.append("    @Override public " + className + " cloneTo(" + className + " o, net.java.html.BrwsrCtx c) { return o.clone(c); }\n");
   2.226 +        w.append("  }\n");
   2.227 +        w.append("  private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n");
   2.228 +        w.append("    this(c);\n");
   2.229 +        int values = 0;
   2.230 +        for (int i = 0; i < propsGetSet.size(); i += 5) {
   2.231 +            Prprt p = findPrprt(props, propsGetSet.get(i));
   2.232 +            if (p == null) {
   2.233 +                continue;
   2.234 +            }
   2.235 +            values++;
   2.236 +        }
   2.237 +        w.append("    Object[] ret = new Object[" + values + "];\n");
   2.238 +        w.append("    proto.extract(json, new String[] {\n");
   2.239 +        for (int i = 0; i < propsGetSet.size(); i += 5) {
   2.240 +            Prprt p = findPrprt(props, propsGetSet.get(i));
   2.241 +            if (p == null) {
   2.242 +                continue;
   2.243 +            }
   2.244 +            w.append("      \"").append(propsGetSet.get(i)).append("\",\n");
   2.245 +        }
   2.246 +        w.append("    }, ret);\n");
   2.247 +        for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) {
   2.248 +            final String pn = propsGetSet.get(i);
   2.249 +            Prprt p = findPrprt(props, pn);
   2.250 +            if (p == null) {
   2.251 +                continue;
   2.252 +            }
   2.253 +            boolean[] isModel = { false };
   2.254 +            boolean[] isEnum = { false };
   2.255 +            boolean isPrimitive[] = { false };
   2.256 +            String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
   2.257 +            if (p.array()) {
   2.258 +                w.append("    if (ret[" + cnt + "] instanceof Object[]) {\n");
   2.259 +                w.append("      for (Object e : ((Object[])ret[" + cnt + "])) {\n");
   2.260 +                if (isModel[0]) {
   2.261 +                    w.append("        this.prop_").append(pn).append(".add(proto.read");
   2.262 +                    w.append("(" + type + ".class, e));\n");
   2.263 +                } else if (isEnum[0]) {
   2.264 +                    w.append("        this.prop_").append(pn);
   2.265 +                    w.append(".add(e == null ? null : ");
   2.266 +                    w.append(type).append(".valueOf(TYPE.stringValue(e)));\n");
   2.267 +                } else {
   2.268 +                    if (isPrimitive(type)) {
   2.269 +                        w.append("        this.prop_").append(pn).append(".add(TYPE.numberValue(e).");
   2.270 +                        w.append(type).append("Value());\n");
   2.271 +                    } else {
   2.272 +                        w.append("        this.prop_").append(pn).append(".add((");
   2.273 +                        w.append(type).append(")e);\n");
   2.274 +                    }
   2.275 +                }
   2.276 +                w.append("      }\n");
   2.277 +                w.append("    }\n");
   2.278 +            } else {
   2.279 +                if (isEnum[0]) {
   2.280 +                    w.append("    try {\n");
   2.281 +                    w.append("    this.prop_").append(pn);
   2.282 +                    w.append(" = ret[" + cnt + "] == null ? null : ");
   2.283 +                    w.append(type).append(".valueOf(TYPE.stringValue(ret[" + cnt + "]));\n");
   2.284 +                    w.append("    } catch (IllegalArgumentException ex) {\n");
   2.285 +                    w.append("      ex.printStackTrace();\n");
   2.286 +                    w.append("    }\n");
   2.287 +                } else if (isPrimitive(type)) {
   2.288 +                    w.append("    this.prop_").append(pn);
   2.289 +                    w.append(" = ret[" + cnt + "] == null ? ");
   2.290 +                    if ("char".equals(type)) {
   2.291 +                        w.append("0 : (TYPE.charValue(");
   2.292 +                    } else if ("boolean".equals(type)) {
   2.293 +                        w.append("false : (TYPE.boolValue(");
   2.294 +                    } else {
   2.295 +                        w.append("0 : (TYPE.numberValue(");
   2.296 +                    }
   2.297 +                    w.append("ret[" + cnt + "])).");
   2.298 +                    w.append(type).append("Value();\n");
   2.299 +                } else if (isModel[0]) {
   2.300 +                    w.append("    this.prop_").append(pn).append(" = proto.read");
   2.301 +                    w.append("(" + type + ".class, ");
   2.302 +                    w.append("ret[" + cnt + "]);\n");
   2.303 +                }else {
   2.304 +                    w.append("    this.prop_").append(pn);
   2.305 +                    w.append(" = (").append(type).append(')');
   2.306 +                    w.append("ret[" + cnt + "];\n");
   2.307 +                }
   2.308 +            }
   2.309 +            cnt++;
   2.310 +        }
   2.311 +        w.append("  }\n");
   2.312 +        writeToString(props, w);
   2.313 +        writeClone(className, props, w);
   2.314 +        w.write("  /** Activates this model instance in the current {@link \n"
   2.315 +            + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n"
   2.316 +            + "In case of using Knockout technology, this means to \n"
   2.317 +            + "bind JSON like data in this model instance with Knockout tags in \n"
   2.318 +            + "the surrounding HTML page.\n"
   2.319 +            + "*/\n"
   2.320 +        );
   2.321 +        w.write("  public " + className + " applyBindings() {\n");
   2.322 +        w.write("    proto.applyBindings();\n");
   2.323 +        w.write("    return this;\n");
   2.324 +        w.write("  }\n");
   2.325 +        w.write("  public boolean equals(Object o) {\n");
   2.326 +        w.write("    if (o == this) return true;\n");
   2.327 +        w.write("    if (!(o instanceof " + className + ")) return false;\n");
   2.328 +        w.write("    " + className + " p = (" + className + ")o;\n");
   2.329 +        for (Prprt p : props) {
   2.330 +            w.write("    if (!TYPE.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n");
   2.331 +        }
   2.332 +        w.write("    return true;\n");
   2.333 +        w.write("  }\n");
   2.334 +        w.write("  public int hashCode() {\n");
   2.335 +        w.write("    int h = " + className + ".class.getName().hashCode();\n");
   2.336 +        for (Prprt p : props) {
   2.337 +            w.write("    h = TYPE.hashPlus(prop_" + p.name() + ", h);\n");
   2.338 +        }
   2.339 +        w.write("    return h;\n");
   2.340 +        w.write("  }\n");
   2.341 +        w.write("}\n");
   2.342 +    }
   2.343 +
   2.344 +    private boolean processEnum(Element e) {
   2.345 +        boolean ok = true;
   2.346 +        Model m = e.getAnnotation(Model.class);
   2.347 +        if (m == null) {
   2.348 +            return true;
   2.349 +        }
   2.350 +        String pkg = findPkgName(e);
   2.351 +        Writer w;
   2.352 +        String className = m.className();
   2.353 +        models.put(e, className);
   2.354 +        try {
   2.355 +            StringWriter body = new StringWriter();
   2.356 +            StringBuilder onReceiveType = new StringBuilder();
   2.357 +            List<String> propsGetSet = new ArrayList<String>();
   2.358 +            List<String> functions = new ArrayList<String>();
   2.359 +            Map<String, Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
   2.360 +            Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
   2.361 +            Prprt[] props = createProps(e, m.properties());
   2.362 +            
   2.363 +            if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
   2.364 +                ok = false;
   2.365 +            }
   2.366 +            if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
   2.367 +                ok = false;
   2.368 +            }
   2.369 +            if (!generateProperties(e, body, className, props, propsGetSet, propsDeps, functionDeps)) {
   2.370 +                ok = false;
   2.371 +            }
   2.372 +            if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
   2.373 +                ok = false;
   2.374 +            }
   2.375 +            if (!generateReceive(e, body, className, e.getEnclosedElements(), onReceiveType)) {
   2.376 +                ok = false;
   2.377 +            }
   2.378 +            if (!generateOperation(e, body, className, e.getEnclosedElements())) {
   2.379 +                ok = false;
   2.380 +            }
   2.381 +            FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
   2.382 +            w = new OutputStreamWriter(java.openOutputStream());
   2.383 +            try {
   2.384 +                w.append("package " + pkg + ";\n");
   2.385 +                w.append("import net.java.html.json.*;\n");
   2.386                  w.append("public final class ").append(className).append(" implements Cloneable {\n");
   2.387                  w.append("  private static final Html4JavaType TYPE = new Html4JavaType();\n");
   2.388                  w.append("  private final org.apidesign.html.json.spi.Proto proto;\n");
   2.389 @@ -260,8 +617,12 @@
   2.390                      }
   2.391                  }
   2.392                  w.append("  };\n");
   2.393 -                if (props.length > 0) {
   2.394 -                    w.append("  public ").append(className).append("(");
   2.395 +                // enum
   2.396 +                StringBuilder factoryHeader = new StringBuilder();
   2.397 +                if (true) {
   2.398 +                    w.write("  private Object union;\n");
   2.399 +                    
   2.400 +                    w.append("  private ").append(className).append("(");
   2.401                      Prprt firstArray = null;
   2.402                      String sep = "";
   2.403                      for (Prprt p : props) {
   2.404 @@ -272,9 +633,9 @@
   2.405                              continue;
   2.406                          }
   2.407                          String tn = typeName(e, p);
   2.408 -                        w.write(sep);
   2.409 -                        w.write(tn);
   2.410 -                        w.write(" " + p.name());
   2.411 +                        w.write(sep); factoryHeader.append(sep);
   2.412 +                        w.write(tn); factoryHeader.append(tn);
   2.413 +                        w.write(" " + p.name()); factoryHeader.append(" " + p.name());
   2.414                          sep = ", ";
   2.415                      }
   2.416                      if (firstArray != null) {
   2.417 @@ -283,10 +644,11 @@
   2.418                          boolean[] isEnum = {false};
   2.419                          boolean isPrimitive[] = {false};
   2.420                          tn = checkType(firstArray, isModel, isEnum, isPrimitive);
   2.421 -                        w.write(sep);
   2.422 -                        w.write(tn);
   2.423 -                        w.write("... " + firstArray.name());
   2.424 +                        w.write(sep); factoryHeader.append(sep);
   2.425 +                        w.write(tn); factoryHeader.append(tn);
   2.426 +                        w.write("... " + firstArray.name()); factoryHeader.append("... " + firstArray.name());
   2.427                      }
   2.428 +                    // end of enum
   2.429                      w.append(") {\n");
   2.430                      w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
   2.431                      for (Prprt p : props) {
   2.432 @@ -491,6 +853,19 @@
   2.433                  }
   2.434                  w.write("    return h;\n");
   2.435                  w.write("  }\n");
   2.436 +                // enum
   2.437 +                w.write("  public " + inPckName(e) + " get" + e.getSimpleName() + "() { return null; }\n");
   2.438 +                for (Element ec : e.getEnclosedElements()) {
   2.439 +                    if (ec.getKind() != ElementKind.ENUM_CONSTANT) {
   2.440 +                        continue;
   2.441 +                    }
   2.442 +                    w.write("    public " + ec.getSimpleName() + " get" + ec.getSimpleName() + "() { return null; }\n");
   2.443 +                    w.write("    public static " + className + " create" + ec.getSimpleName() + " (" + ec.getSimpleName() + " union, ");
   2.444 +                    w.write(factoryHeader.toString());
   2.445 +                    w.write(") { return null; }\n");
   2.446 +                    generateEnumConstantModel(w, ec);
   2.447 +                }
   2.448 +                // end of enum
   2.449                  w.write("}\n");
   2.450              } finally {
   2.451                  w.close();
   2.452 @@ -502,6 +877,50 @@
   2.453          return ok;
   2.454      }
   2.455      
   2.456 +    private boolean generateEnumConstantModel(Writer w, Element ec) throws IOException {
   2.457 +        Model m = ec.getAnnotation(Model.class);
   2.458 +        if (m == null) {
   2.459 +            error("Each field in an enum needs to be annotated by @Model", ec);
   2.460 +            return false;
   2.461 +        }
   2.462 +        boolean ok = true;
   2.463 +        
   2.464 +        String className = m.className();
   2.465 +        
   2.466 +        StringWriter body = new StringWriter();
   2.467 +        StringBuilder onReceiveType = new StringBuilder();
   2.468 +        List<String> propsGetSet = new ArrayList<String>();
   2.469 +        List<String> functions = new ArrayList<String>();
   2.470 +        Map<String, Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
   2.471 +        Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
   2.472 +        Prprt[] props = createProps(ec, m.properties());
   2.473 +
   2.474 +//        if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
   2.475 +//            ok = false;
   2.476 +//        }
   2.477 +//        if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
   2.478 +//            ok = false;
   2.479 +//        }
   2.480 +        if (!generateProperties(ec, body, className, props, propsGetSet, propsDeps, functionDeps)) {
   2.481 +            ok = false;
   2.482 +        }
   2.483 +//        if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
   2.484 +//            ok = false;
   2.485 +//        }
   2.486 +//        if (!generateReceive(e, body, className, e.getEnclosedElements(), onReceiveType)) {
   2.487 +//            ok = false;
   2.488 +//        }
   2.489 +        onReceiveType.append("  @Override public void onMessage(").append(className).append(" model, int index, int type, Object data) {\n");
   2.490 +        onReceiveType.append("  }\n");
   2.491 +        
   2.492 +//        if (!generateOperation(e, body, className, e.getEnclosedElements())) {
   2.493 +//            ok = false;
   2.494 +//        }
   2.495 +        w.write("    public static final ");
   2.496 +        generateClassBody(w, className, body, ec, props, functionDeps, propsDeps, propsGetSet, functions, onReceiveType);
   2.497 +        return ok;
   2.498 +    }
   2.499 +    
   2.500      private boolean generateProperties(
   2.501          Element where,
   2.502          Writer w, String className, Prprt[] properties,
   2.503 @@ -1398,6 +1817,10 @@
   2.504      }
   2.505  
   2.506      private String inPckName(Element e) {
   2.507 +        while (!(e instanceof TypeElement)) {
   2.508 +            e = e.getEnclosingElement();
   2.509 +        }
   2.510 +        
   2.511          StringBuilder sb = new StringBuilder();
   2.512          while (e.getKind() != ElementKind.PACKAGE) {
   2.513              if (sb.length() == 0) {
   2.514 @@ -1671,12 +2094,8 @@
   2.515                  return new Prprt[0];
   2.516              }
   2.517              
   2.518 -            if (e.getKind() != ElementKind.CLASS) {
   2.519 -                throw new IllegalStateException("" + e.getKind());
   2.520 -            }
   2.521 -            TypeElement te = (TypeElement)e;
   2.522              List<? extends AnnotationValue> val = null;
   2.523 -            for (AnnotationMirror an : te.getAnnotationMirrors()) {
   2.524 +            for (AnnotationMirror an : e.getAnnotationMirrors()) {
   2.525                  for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : an.getElementValues().entrySet()) {
   2.526                      if (entry.getKey().getSimpleName().contentEquals("properties")) {
   2.527                          val = (List)entry.getValue().getValue();
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/PlainEnumTest.java	Fri Jan 24 13:15:30 2014 +0100
     3.3 @@ -0,0 +1,93 @@
     3.4 +/**
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
     3.8 + *
     3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    3.10 + * Other names may be trademarks of their respective owners.
    3.11 + *
    3.12 + * The contents of this file are subject to the terms of either the GNU
    3.13 + * General Public License Version 2 only ("GPL") or the Common
    3.14 + * Development and Distribution License("CDDL") (collectively, the
    3.15 + * "License"). You may not use this file except in compliance with the
    3.16 + * License. You can obtain a copy of the License at
    3.17 + * http://www.netbeans.org/cddl-gplv2.html
    3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.19 + * specific language governing permissions and limitations under the
    3.20 + * License.  When distributing the software, include this License Header
    3.21 + * Notice in each file and include the License file at
    3.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    3.23 + * particular file as subject to the "Classpath" exception as provided
    3.24 + * by Oracle in the GPL Version 2 section of the License file that
    3.25 + * accompanied this code. If applicable, add the following below the
    3.26 + * License Header, with the fields enclosed by brackets [] replaced by
    3.27 + * your own identifying information:
    3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.29 + *
    3.30 + * Contributor(s):
    3.31 + *
    3.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    3.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    3.34 + *
    3.35 + * If you wish your version of this file to be governed by only the CDDL
    3.36 + * or only the GPL Version 2, indicate your decision by adding
    3.37 + * "[Contributor] elects to include this software in this distribution
    3.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.39 + * single choice of license, a recipient has the option to distribute
    3.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    3.41 + * to extend the choice of license to its licensees as provided above.
    3.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.43 + * Version 2 license, then the option applies only if the new code is
    3.44 + * made subject to such option by the copyright holder.
    3.45 + */
    3.46 +package org.netbeans.html.json.impl;
    3.47 +
    3.48 +import net.java.html.json.Model;
    3.49 +import net.java.html.json.Property;
    3.50 +import static org.testng.Assert.*;
    3.51 +import org.testng.annotations.Test;
    3.52 +
    3.53 +/**
    3.54 + *
    3.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.56 + */
    3.57 +public class PlainEnumTest {
    3.58 +    @Test public void unionA() {
    3.59 +        Union on = Union.createA(new Union.A(9), 11, 1.1);
    3.60 +        assertEquals(on.getX(), 11);
    3.61 +        assertEquals(on.getY(), 1.1);
    3.62 +        
    3.63 +        assertEquals(on.getAbc(), Abc.A);
    3.64 +        assertNotNull(on.getA());
    3.65 +        assertEquals(on.getA().getUa(), 9);
    3.66 +        assertNull(on.getB());
    3.67 +    }
    3.68 +
    3.69 +    @Test public void unionB() {
    3.70 +        Union on = Union.createB(new Union.B("9.9"), 11, 1.1);
    3.71 +        assertEquals(on.getX(), 11);
    3.72 +        assertEquals(on.getY(), 1.1);
    3.73 +        
    3.74 +        assertEquals(on.getAbc(), Abc.A);
    3.75 +        assertNull(on.getA());
    3.76 +        assertNotNull(on.getB());
    3.77 +        assertEquals(on.getB().getUb(), "9.9");
    3.78 +    }
    3.79 +
    3.80 +
    3.81 +    
    3.82 +    @Model(className = "Union", properties = {
    3.83 +        @Property(name = "x", type = int.class),
    3.84 +        @Property(name = "y", type = double.class)
    3.85 +    })
    3.86 +    enum Abc {
    3.87 +        @Model(className = "A", properties = { 
    3.88 +            @Property(name = "ua", type = int.class)
    3.89 +        })
    3.90 +        A, 
    3.91 +        @Model(className = "B", properties = { 
    3.92 +            @Property(name = "ub", type = String.class)
    3.93 +        })
    3.94 +        B
    3.95 +    }
    3.96 +}