json/src/main/java/net/java/html/json/Model.java
author Jaroslav Tulach <jtulach@netbeans.org>
Fri, 12 Dec 2014 12:37:58 +0100
changeset 904 6505c38a43b3
parent 881 640ff17529f8
child 920 117b732d42d0
permissions -rw-r--r--
Fixing Javadoc warnings
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package net.java.html.json;
    44 
    45 import java.lang.annotation.ElementType;
    46 import java.lang.annotation.Retention;
    47 import java.lang.annotation.RetentionPolicy;
    48 import java.lang.annotation.Target;
    49 import java.net.URL;
    50 import java.util.List;
    51 
    52 /** Defines a model class that represents a single 
    53  * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>-like object
    54  * named {@link #className()}. The generated class contains
    55  * getters and setters for properties defined via {@link #properties()} and
    56  * getters for other, derived properties defined by annotating methods
    57  * of this class by {@link ComputedProperty}. Each property
    58  * can be of primitive type, an {@link Enum enum type} or (in order to create 
    59  * nested <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> structure)
    60  * of another {@link Model class generated by @Model} annotation. Each property
    61  * can either represent a single value or be an array of its values.
    62  * <p>
    63  * The {@link #className() generated class}'s <code>toString</code> method
    64  * converts the state of the object into 
    65  * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> format. One can
    66  * use {@link Models#parse(net.java.html.BrwsrCtx, java.lang.Class, java.io.InputStream)}
    67  * method to read the JSON text stored in a file or other stream back into the Java model. 
    68  * One can also use {@link OnReceive @OnReceive} annotation to read the model
    69  * asynchronously from a {@link URL}.
    70  * <p>
    71  * An example where one defines class <code>Person</code> with four
    72  * properties (<code>firstName</code>, <code>lastName</code>, array of <code>addresses</code> and
    73  * <code>fullName</code>) follows:
    74  * <pre>
    75  * {@link Model @Model}(className="Person", properties={
    76  *   {@link Property @Property}(name = "firstName", type=String.<b>class</b>),
    77  *   {@link Property @Property}(name = "lastName", type=String.<b>class</b>)
    78  *   {@link Property @Property}(name = "addresses", type=Address.<b>class</b>, array = <b>true</b>)
    79  * })
    80  * <b>static class</b> PersonModel {
    81  *   {@link ComputedProperty @ComputedProperty}
    82  *   <b>static</b> String fullName(String firstName, String lastName) {
    83  *     <b>return</b> firstName + " " + lastName;
    84  *   }
    85  * 
    86  *   {@link ComputedProperty @ComputedProperty}
    87  *   <b>static</b> String mainAddress({@link List List&lt;Address&gt;} addresses) {
    88  *     <b>for</b> (Address a : addresses) {
    89  *       <b>return</b> a.getStreet() + " " + a.getTown();
    90  *     }
    91  *     <b>return</b> "No address";
    92  *   }
    93  * 
    94  *   {@link Model @Model}(className="Address", properties={
    95  *     {@link Property @Property}(name = "street", type=String.<b>class</b>),
    96  *     {@link Property @Property}(name = "town", type=String.<b>class</b>)
    97  *   })
    98  *   <b>static class</b> AddressModel {
    99  *   }
   100  * }
   101  * </pre>
   102  * The generated model class has a default constructor, and also <em>quick
   103  * instantiation</em> constructor that accepts all non-array properties 
   104  * (in the order used in the {@link #properties()} attribute) and vararg list
   105  * for the first array property (if any). One can thus use following code
   106  * to create an instance of the Person and Address classes:
   107  * <pre>
   108  * Person p = <b>new</b> Person("Jaroslav", "Tulach",
   109  *   <b>new</b> Address("Markoušovice", "Úpice"),
   110  *   <b>new</b> Address("V Parku", "Praha")
   111  * );
   112  * // p.toString() then returns equivalent of following <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> object
   113  * {
   114  *   "firstName" : "Jaroslav",
   115  *   "lastName" : "Tulach",
   116  *   "addresses" : [
   117  *     { "street" : "Markoušovice", "town" : "Úpice" },
   118  *     { "street" : "V Parku", "town" : "Praha" },
   119  *   ]
   120  * }
   121  * </pre>
   122  * <p>
   123  * In case you are using <a target="_blank" href="http://knockoutjs.com/">Knockout technology</a>
   124  * for Java then you can associate such model object with surrounding HTML page by
   125  * calling: <code>p.applyBindings();</code>. The page can then use regular
   126  * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> bindings to reference your
   127  * model and create dynamic connection between your model in Java and 
   128  * live DOM structure in the browser:
   129  * </p>
   130  * <pre>
   131  * Name: &lt;span data-bind="text: fullName"&gt;
   132  * &lt;div data-bind="foreach: addresses"&gt;
   133  *   Lives in &lt;span data-bind="text: town"/&gt;
   134  * &lt;/div&gt;
   135  * </pre>
   136  * 
   137  * <h3>Access Raw <a target="_blank" href="http://knockoutjs.com/">Knockout</a> Observables</h3>
   138  * 
   139  * One can obtain <em>raw</em> JavaScript object representing the 
   140  * instance of {@link Model model class} (with appropriate
   141  * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> <b>observable</b> properties)
   142  * by calling {@link Models#toRaw(java.lang.Object) Models.toRaw(p)}. For 
   143  * example here is a way to obtain the value of <code>fullName</code> property
   144  * (inefficient as it switches between Java and JavaScript back and forth, 
   145  * but functional and instructive) via a JavaScript call:
   146  * <pre>
   147  * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = "raw", javacall = true, body =
   148  *   "return raw.fullName();" // yes, the <a target="_blank" href="http://knockoutjs.com/">Knockout</a> property is a function
   149  * )
   150  * static native String jsFullName(Object raw);
   151  * // and later
   152  * Person p = ...;
   153  * String fullName = jsFullName({@link Models#toRaw(java.lang.Object) Models.toRaw(p)});
   154  * </pre>
   155  * The above shows how to read a value from <a target="_blank" href="http://knockoutjs.com/">Knockout</a>
   156  * observable. There is a way to change the value too:
   157  * One can pass a parameter to the property-function and then
   158  * it acts like a setter (of course not in the case of read only <code>fullName</code> property,
   159  * but for <code>firstName</code> or <code>lastName</code> the setter is
   160  * available). Everything mentioned in this paragraph applies only when 
   161  * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> technology is active
   162  * other technologies may behave differently.
   163  * 
   164  * <h4>Copy to Plain JSON</h4>
   165  * There is a way to pass a value of a Java {@link Model model class} instance 
   166  * by copy and convert 
   167  * the {@link Model the whole object} into plain 
   168  * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>. Just
   169  * print it as a string and parse it in JavaScript:
   170  * <pre>
   171  * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = { "txt" }, body =
   172  *   "return JSON.parse(txt);"
   173  * )
   174  * private static native Object parseJSON(String txt);
   175  * 
   176  * public static Object toPlainJSON(Object model) {
   177  *   return parseJSON(model.toString());
   178  * }
   179  * </pre>
   180  * The newly returned instance is a one time copy of the original model and is no longer
   181  * connected to it. The copy based behavior is independent on any 
   182  * particular technology and should work
   183  * in <a target="_blank" href="http://knockoutjs.com/">Knockout</a> as well as other
   184  * technology implementations.
   185  * 
   186  * <h4>References</h4>
   187  * 
   188  * Visit an <a target="_blank" href="http://dew.apidesign.org/dew/#7510833">on-line demo</a>
   189  * to see a histogram driven by the {@link Model} annotation or try 
   190  * a little <a target="_blank" href="http://dew.apidesign.org/dew/#7263102">math test</a>.
   191  *
   192  * @author Jaroslav Tulach
   193  */
   194 @Retention(RetentionPolicy.SOURCE)
   195 @Target(ElementType.TYPE)
   196 public @interface Model {
   197     /** Name of the model class.
   198      * @return valid Java identifier to use as a name of the model class
   199      */
   200     String className();
   201     /** List of properties in the model.
   202      * @return array of property definitions
   203      */
   204     Property[] properties();
   205 }