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