2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
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]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
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.
43 package org.netbeans.html.json.spi;
45 import java.util.Collection;
46 import java.util.List;
47 import net.java.html.BrwsrCtx;
48 import net.java.html.json.ComputedProperty;
49 import net.java.html.json.Model;
50 import org.netbeans.html.json.impl.Bindings;
51 import org.netbeans.html.json.impl.JSON;
52 import org.netbeans.html.json.impl.JSONList;
53 import org.netbeans.html.json.impl.RcvrJSON;
54 import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
56 /** Object associated with one instance of a model generated by the
57 * {@link Model} annotation. Contains methods the generated class can
58 * use to communicate with behind the scene associated {@link Technology}.
59 * Each {@link Proto} object is associated with <a href="http://wiki.apidesign.org/wiki/Singletonizer">
60 * singletonizer</a>-like interface {@link Type} which provides the
61 * associated {@link Technology} the necessary information about the
62 * generated {@link Model} class.
64 * @author Jaroslav Tulach
67 public final class Proto {
68 private final Object obj;
69 private final Type type;
70 private final net.java.html.BrwsrCtx context;
71 private org.netbeans.html.json.impl.Bindings ko;
72 private Observers observers;
74 Proto(Object obj, Type type, BrwsrCtx context) {
77 this.context = context;
80 /** Browser context this proto object and its associated model
83 * @return the associated context
85 public BrwsrCtx getContext() {
89 /** Acquires global lock to compute a {@link ComputedProperty derived property}
90 * on this proto object. This proto object must not be locked yet. No
91 * dependency tracking is performed.
93 * @throws IllegalStateException if already locked
95 public void acquireLock() throws IllegalStateException {
99 /** Acquires global lock to compute a {@link ComputedProperty derived property}
100 * on this proto object. This proto object must not be locked yet. The
101 * name of the property is used to track dependencies on own
102 * properties of other proto objects - when they are changed, this
103 * {@link #valueHasMutated(java.lang.String) property is changed too}.
105 * @param propName name of property we are about to compute
106 * @throws IllegalStateException thrown when there is a cyclic
110 public void acquireLock(String propName) throws IllegalStateException {
111 Observers.beginComputing(this, propName);
114 /** A property on this proto object is about to be accessed. Verifies
115 * whether this proto object is accessible - e.g. it has not been
116 * {@link #acquireLock() locked yet}. If everything is OK, the
117 * <code>propName</code> is recorded in the chain of dependencies
118 * tracked by {@link #acquireLock(java.lang.String)} and watched by
119 * {@link #valueHasMutated(java.lang.String)}.
121 * @param propName name of the property that is requested
122 * @throws IllegalStateException if the model is locked
125 public void accessProperty(String propName) throws IllegalStateException {
126 Observers.accessingValue(this, propName);
129 /** Verifies the model is not locked otherwise throws an exception.
130 * @throws IllegalStateException if the model is locked
132 public void verifyUnlocked() throws IllegalStateException {
133 Observers.verifyUnlocked(this);
136 /** When modifications are over, the model is switched into
137 * unlocked state by calling this method.
139 public void releaseLock() {
140 Observers.finishComputing(this);
143 /** Whenever model changes a property. It should notify the
144 * associated technology by calling this method.
145 * Since 0.8.3: This method may be called by any thread - it reschedules
146 * its actual execution into appropriate one by using
147 * {@link BrwsrCtx#execute(java.lang.Runnable)}.
149 * @param propName name of the changed property
151 public void valueHasMutated(final String propName) {
152 context.execute(new Runnable() {
156 ko.valueHasMutated(propName, null, null);
158 Observers.valueHasMutated(Proto.this, propName);
163 /** Whenever model changes a propertyit should notify the
164 * associated technology. Either by calling this method
165 * (if the new value is known and different to the old one) or
166 * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
168 * Since 0.8.3: This method may be called by any thread - it reschedules
169 * its actual execution into appropriate one by using
170 * {@link BrwsrCtx#execute(java.lang.Runnable)}.
172 * @param propName name of the changed property
173 * @param oldValue provides previous value of the property
174 * @param newValue provides new value of the property
177 public void valueHasMutated(
178 final String propName, final Object oldValue, final Object newValue
180 context.execute(new Runnable() {
184 ko.valueHasMutated(propName, oldValue, newValue);
186 Observers.valueHasMutated(Proto.this, propName);
191 /** Initializes the associated model in the current {@link #getContext() context}.
192 * In case of <em>knockout.js</em> technology, applies given bindings
193 * of the current model to the <em>body</em> element of the page.
195 public void applyBindings() {
196 initBindings().applyBindings(null);
199 /** Initializes the associated model to the specified element's subtree.
200 * The technology is taken from the current {@link #getContext() context} and
201 * in case of <em>knockout.js</em> applies given bindings
202 * of the current model to the element of the page with 'id' attribute
203 * set to the specified <code>id</code> value.
205 * @param id the id of element to apply the binding to
207 * @see Technology.ApplyId
209 public void applyBindings(String id) {
210 initBindings().applyBindings(id);
213 /** Invokes the provided runnable in the {@link #getContext() context}
214 * of the browser. If the caller is already on the right thread, the
215 * <code>run.run()</code> is invoked immediately and synchronously.
216 * Otherwise the method returns immediately and the <code>run()</code>
217 * method is performed later
219 * @param run the action to execute
221 public void runInBrowser(Runnable run) {
222 context.execute(run);
225 /** Invokes the specified function index in the {@link #getContext() context}
226 * of the browser. If the caller is already on the right thread, the
227 * index-th function is invoked immediately and synchronously.
228 * Otherwise the method returns immediately and the function is invoked
231 * @param index the index of the function as will be passed to
232 * {@link Type#call(java.lang.Object, int, java.lang.Object, java.lang.Object)}
234 * @param args array of arguments that will be passed as
235 * <code>data</code> argument of the <code>call</code> method.
238 public void runInBrowser(final int index, final Object... args) {
239 context.execute(new Runnable() {
243 type.call(obj, index, args, null);
244 } catch (Exception ex) {
245 ex.printStackTrace();
251 /** Initializes the provided collection with a content of the <code>array</code>.
252 * The initialization can only be done soon after the the collection
253 * is created, otherwise an exception is throw
255 * @param to the collection to initialize (assumed to be empty)
256 * @param array the array to add to the collection
257 * @throws IllegalStateException if the system has already been initialized
259 public void initTo(Collection<?> to, Object array) {
261 throw new IllegalStateException();
263 if (to instanceof JSONList) {
264 ((JSONList)to).init(array);
266 JSONList.init(to, array);
270 /** Takes an object representing JSON result and extract some of its
271 * properties. It is assumed that the <code>props</code> and
272 * <code>values</code> arrays have the same length.
274 * @param json the JSON object (actual type depends on the associated
275 * {@link Technology})
276 * @param props list of properties to extract
277 * @param values array that will be filled with extracted values
279 public void extract(Object json, String[] props, Object[] values) {
280 JSON.extract(context, json, props, values);
283 /** Converts raw JSON <code>data</code> into a Java {@link Model} class.
285 * @param <T> type of the model class
286 * @param modelClass the type of the class to create
287 * @param data the raw JSON data
288 * @return newly created instance of the model class
290 public <T> T read(Class<T> modelClass, Object data) {
291 return JSON.read(context, modelClass, data);
294 /** Initializes asynchronous JSON connection to specified URL. Delegates
295 * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
296 * with no extra parameters.
298 * @param index the callback index to be used when a reply is received
299 * to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
301 * @param urlBefore the part of the URL before JSON-P callback parameter
302 * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
303 * @param method method to use for connection to the server
304 * @param data string, number or a {@link Model} generated class to send to
305 * the server when doing a query
307 public void loadJSON(final int index,
308 String urlBefore, String urlAfter, String method,
311 loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
314 /** Initializes asynchronous JSON connection to specified URL. The
315 * method returns immediately and later does callback later.
317 * @param index the callback index to be used when a reply is received
318 * to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
320 * @param urlBefore the part of the URL before JSON-P callback parameter
321 * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
322 * @param method method to use for connection to the server
323 * @param data string, number or a {@link Model} generated class to send to
324 * the server when doing a query
325 * @param params extra params to pass back when calling
326 * {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
329 public void loadJSON(final int index,
330 String urlBefore, String urlAfter, String method,
331 final Object data, final Object... params
333 class Rcvr extends RcvrJSON {
335 protected void onMessage(MsgEvnt msg) {
336 type.onMessage(obj, index, 1, msg.getValues(), params);
340 protected void onError(MsgEvnt msg) {
341 type.onMessage(obj, index, 2, msg.getException(), params);
344 JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
347 /** Opens new WebSocket connection to the specified URL.
349 * @param index the index to use later during callbacks to
350 * {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}
351 * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to
352 * @param data data to send to server (usually <code>null</code>)
353 * @return returns a non-null object representing the socket
354 * which can be used when calling {@link #wsSend(java.lang.Object, java.lang.String, java.lang.Object) }
356 public Object wsOpen(final int index, String url, Object data) {
357 class WSrcvr extends RcvrJSON {
359 protected void onError(MsgEvnt msg) {
360 type.onMessage(obj, index, 2, msg.getException());
364 protected void onMessage(MsgEvnt msg) {
365 type.onMessage(obj, index, 1, msg.getValues());
369 protected void onClose(MsgEvnt msg) {
370 type.onMessage(obj, index, 3, null);
374 protected void onOpen(MsgEvnt msg) {
375 type.onMessage(obj, index, 0, null);
378 return JSON.openWS(context, new WSrcvr(), url, data);
381 /** Sends a message to existing socket.
383 * @param webSocket the socket to send message to
384 * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to,
385 * preferably the same as the one used when the socket was
386 * {@link #wsOpen(int, java.lang.String, java.lang.Object) opened}
387 * @param data the data to send or <code>null</code> if the socket is
388 * supposed to be closed
390 public void wsSend(Object webSocket, String url, Object data) {
391 ((JSON.WS)webSocket).send(context, url, data);
394 /** Converts raw data (one of its properties) to string representation.
396 * @param data the object
397 * @param propName the name of object property or <code>null</code>
398 * if the whole object should be converted
399 * @return the string representation of the object or its property
401 public String toString(Object data, String propName) {
402 return JSON.toString(context, data, propName);
405 /** Converts raw data (one of its properties) to a number representation.
407 * @param data the object
408 * @param propName the name of object property or <code>null</code>
409 * if the whole object should be converted
410 * @return the number representation of the object or its property
412 public Number toNumber(Object data, String propName) {
413 return JSON.toNumber(context, data, propName);
416 /** Converts raw JSON data into a {@link Model} class representation.
418 * @param <T> type of the model to create
419 * @param type class of the model to create
420 * @param data raw JSON data (depends on associated {@link Technology})
421 * @return new instances of the model class filled with values from the
422 * <code>data</code> object
424 public <T> T toModel(Class<T> type, Object data) {
425 return JSON.toModel(context, type, data, null);
428 /** Creates new JSON like observable list.
430 * @param <T> the type of the list elements
431 * @param propName name of a property this list is associated with
432 * @param onChange index of the property to use when the list is modified
433 * during callback to {@link Type#onChange(java.lang.Object, int)}
434 * @param dependingProps the array of {@link ComputedProperty derived properties}
435 * that depend on the value of the list
436 * @return new, empty list associated with this proto-object and its model
438 public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
439 return new JSONList<T>(this, propName, onChange, dependingProps);
442 /** Copies content of one collection to another, re-assigning all its
443 * elements from their current context to the new <code>ctx</code>.
445 * @param <T> type of the collections
446 * @param to the target collection to be filled with cloned values
447 * @param ctx context for the new collection
448 * @param from original collection with its data
450 public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
451 Boolean isModel = null;
453 if (isModel == null) {
454 isModel = JSON.isModel(t.getClass());
457 to.add(JSON.bindTo(t, ctx));
468 final String toStr() {
469 return "Proto[" + obj + "]@" + Integer.toHexString(System.identityHashCode(this));
472 final Bindings initBindings() {
474 Bindings b = Bindings.apply(context, obj);
475 PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
476 for (int i = 0; i < pb.length; i++) {
477 pb[i] = b.registerProperty(
478 type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
481 FunctionBinding[] fb = new FunctionBinding[type.functions.length];
482 for (int i = 0; i < fb.length; i++) {
483 fb[i] = FunctionBinding.registerFunction(
484 type.functions[i], i, obj, type
488 b.finish(obj, pb, fb);
493 final Bindings getBindings() {
497 final void onChange(int index) {
498 type.onChange(obj, index);
501 final Observers observers(boolean create) {
502 if (create && observers == null) {
503 observers = new Observers();
508 /** Functionality used by the code generated by annotation
509 * processor for the {@link net.java.html.json.Model} annotation.
511 * @param <Model> the generated class
514 public static abstract class Type<Model> {
515 private final Class<Model> clazz;
516 private final String[] propertyNames;
517 private final boolean[] propertyReadOnly;
518 private final String[] functions;
520 /** Constructor for subclasses generated by the annotation processor
521 * associated with {@link net.java.html.json.Model} annotation.
523 * @param clazz the generated model class
524 * @param modelFor the original class annotated by the {@link net.java.html.json.Model} annotation.
525 * @param properties number of properties the class has
526 * @param functions number of functions the class has
529 Class<Model> clazz, Class<?> modelFor, int properties, int functions
531 assert getClass().getName().endsWith("$Html4JavaType");
533 assert getClass().getDeclaringClass() == clazz;
534 } catch (SecurityException ex) {
538 this.propertyNames = new String[properties];
539 this.propertyReadOnly = new boolean[properties];
540 this.functions = new String[functions];
541 JSON.register(clazz, this);
544 /** Registers property for the type. It is expected each index
545 * is initialized only once.
547 * @param name name of the property
548 * @param index index of the property
549 * @param readOnly is the property read only?
551 protected final void registerProperty(String name, int index, boolean readOnly) {
552 assert propertyNames[index] == null;
553 propertyNames[index] = name;
554 propertyReadOnly[index] = readOnly;
557 /** Registers function of given name at given index.
559 * @param name name of the function
560 * @param index name of the type
562 protected final void registerFunction(String name, int index) {
563 assert functions[index] == null;
564 functions[index] = name;
567 /** Creates new proto-object for given {@link Model} class bound to
570 * @param obj instance of appropriate {@link Model} class
571 * @param context the browser context
572 * @return new proto-object that the generated class can use for
573 * communication with the infrastructure
575 public Proto createProto(Object obj, BrwsrCtx context) {
576 return new Proto(obj, this, context);
580 // Implemented by subclasses
583 /** Sets value of a {@link #registerProperty(java.lang.String, int, boolean) registered property}
586 * @param model the instance of {@link Model model class}
587 * @param index index of the property used during registration
588 * @param value the value to set the property to
590 protected abstract void setValue(Model model, int index, Object value);
592 /** Obtains and returns value of a
593 * {@link #registerProperty(java.lang.String, int, boolean) registered property}.
595 * @param model the instance of {@link Model model class}
596 * @param index index of the property used during registration
597 * @return current value of the property
599 protected abstract Object getValue(Model model, int index);
601 /** Invokes a {@link #registerFunction(java.lang.String, int)} registered function
604 * @param model the instance of {@link Model model class}
605 * @param index index of the property used during registration
606 * @param data the currently selected object the function is about to operate on
607 * @param event the event that triggered the event
608 * @throws Exception the method can throw exception which is then logged
610 protected abstract void call(Model model, int index, Object data, Object event)
613 /** Re-binds the model object to new browser context.
615 * @param model the instance of {@link Model model class}
616 * @param ctx browser context to clone the object to
617 * @return new instance of the model suitable for new context
619 protected abstract Model cloneTo(Model model, BrwsrCtx ctx);
621 /** Reads raw JSON data and converts them to our model class.
623 * @param c the browser context to work in
624 * @param json raw JSON data to get values from
625 * @return new instance of model class filled by the data
627 protected abstract Model read(BrwsrCtx c, Object json);
629 /** Called when a {@link #registerProperty(java.lang.String, int, boolean) registered property}
632 * @param model the object that has the property
633 * @param index the index of the property during registration
635 protected abstract void onChange(Model model, int index);
637 /** Finds out if there is an associated proto-object for given
640 * @param object an object, presumably (but not necessarily) instance of Model class
641 * @return associated proto-object or <code>null</code>
643 protected abstract Proto protoFor(Object object);
645 /** Called to report results of asynchronous over-the-wire
646 * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
647 * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
649 * @param model the instance of the model class
650 * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
651 * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
652 * not all messages are applicable to all communication protocols (JSON has only 1 and 2).
653 * @param data <code>null</code> or string, number or a {@link Model} class
654 * obtained to the server as a response
656 protected void onMessage(Model model, int index, int type, Object data) {
657 onMessage(model, index, type, data, new Object[0]);
660 /** Called to report results of asynchronous over-the-wire
661 * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
662 * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
664 * @param model the instance of the model class
665 * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
666 * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
667 * not all messages are applicable to all communication protocols (JSON has only 1 and 2).
668 * @param data <code>null</code> or string, number or a {@link Model} class
669 * obtained to the server as a response
670 * @param params extra parameters as passed for example to
671 * {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
675 protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
676 onMessage(model, index, type, data);
680 // Various support methods the generated classes use
683 /** Converts and array of raw JSON objects into an array of typed
684 * Java {@link Model} classes.
686 * @param <T> the type of the destination array
687 * @param context browser context to use
688 * @param src array of raw JSON objects
689 * @param destType type of the individual array elements
690 * @param dest array to be filled with read type instances
692 public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
693 for (int i = 0; i < src.length && i < dest.length; i++) {
694 dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
698 /** Compares two objects that can be converted to integers.
699 * @param a first value
700 * @param b second value
701 * @return true if they are the same
703 public final boolean isSame(int a, int b) {
707 /** Compares two objects that can be converted to (floating point)
709 * @param a first value
710 * @param b second value
711 * @return true if they are the same
713 public final boolean isSame(double a, double b) {
717 /** Compares two objects for being the same - e.g. either <code>==</code>
718 * or <code>equals</code>.
719 * @param a first value
720 * @param b second value
721 * @return true if they are equals
723 public final boolean isSame(Object a, Object b) {
727 if (a == null || b == null) {
733 /** Cumulative hash function. Adds hashcode of the object to the
735 * @param o the object (or <code>null</code>)
736 * @param h the previous value of the hash
737 * @return new hash - the old one xor the object's one
739 public final int hashPlus(Object o, int h) {
740 return o == null ? h : h ^ o.hashCode();
743 /** Converts an object to its JSON value.
745 * @param obj the object to convert
746 * @return JSON representation of the object
748 public final String toJSON(Object obj) {
749 return JSON.toJSON(obj);
752 /** Converts the value to string.
754 * @param val the value
755 * @return the converted value
757 public final String stringValue(Object val) {
758 return JSON.stringValue(val);
761 /** Converts the value to number.
763 * @param val the value
764 * @return the converted value
766 public final Number numberValue(Object val) {
767 return JSON.numberValue(val);
770 /** Converts the value to character.
772 * @param val the value
773 * @return the converted value
775 public final Character charValue(Object val) {
776 return JSON.charValue(val);
779 /** Converts the value to boolean.
781 * @param val the value
782 * @return the converted value
784 public final Boolean boolValue(Object val) {
785 return JSON.boolValue(val);
788 /** Extracts value of specific type from given object.
790 * @param <T> the type of object one is interested in
791 * @param type the type
792 * @param val the object to convert to type
793 * @return the converted value
795 public final <T> T extractValue(Class<T> type, Object val) {
796 if (Number.class.isAssignableFrom(type)) {
797 val = numberValue(val);
799 if (Boolean.class == type) {
800 val = boolValue(val);
802 if (String.class == type) {
803 val = stringValue(val);
805 if (Character.class == type) {
806 val = charValue(val);
808 if (Integer.class == type) {
809 val = val instanceof Number ? ((Number) val).intValue() : 0;
811 if (Long.class == type) {
812 val = val instanceof Number ? ((Number) val).longValue() : 0;
814 if (Short.class == type) {
815 val = val instanceof Number ? ((Number) val).shortValue() : 0;
817 if (Byte.class == type) {
818 val = val instanceof Number ? ((Number) val).byteValue() : 0;
820 if (Double.class == type) {
821 val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
823 if (Float.class == type) {
824 val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
826 if (type.isEnum() && val instanceof String) {
827 val = Enum.valueOf(type.asSubclass(Enum.class), (String)val);
829 return type.cast(val);
832 /** Special dealing with array & {@link List} values. This method
833 * takes the provided collection, empties it and fills it again
834 * with values extracted from <code>value</code> (which is supposed
837 * @param <T> the type of list elements
838 * @param arr collection to fill with elements in value
839 * @param type the type of elements in the collection
840 * @param value array of elements to put into the collecition. If
841 * value is not an array it is wrapped into array with only element
844 public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
846 if (value instanceof Object[]) {
847 newArr = (Object[]) value;
849 newArr = new Object[] { value };
852 for (Object e : newArr) {
853 arr.add(extractValue(type, e));