During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
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();
199 /** Invokes the provided runnable in the {@link #getContext() context}
200 * of the browser. If the caller is already on the right thread, the
201 * <code>run.run()</code> is invoked immediately and synchronously.
202 * Otherwise the method returns immediately and the <code>run()</code>
203 * method is performed later
205 * @param run the action to execute
207 public void runInBrowser(Runnable run) {
208 context.execute(run);
211 /** Invokes the specified function index in the {@link #getContext() context}
212 * of the browser. If the caller is already on the right thread, the
213 * index-th function is invoked immediately and synchronously.
214 * Otherwise the method returns immediately and the function is invoked
217 * @param index the index of the function as will be passed to
218 * {@link Type#call(java.lang.Object, int, java.lang.Object, java.lang.Object)}
220 * @param args array of arguments that will be passed as
221 * <code>data</code> argument of the <code>call</code> method.
224 public void runInBrowser(final int index, final Object... args) {
225 context.execute(new Runnable() {
229 type.call(obj, index, args, null);
230 } catch (Exception ex) {
231 ex.printStackTrace();
237 /** Initializes the provided collection with a content of the <code>array</code>.
238 * The initialization can only be done soon after the the collection
239 * is created, otherwise an exception is throw
241 * @param to the collection to initialize (assumed to be empty)
242 * @param array the array to add to the collection
243 * @throws IllegalStateException if the system has already been initialized
245 public void initTo(Collection<?> to, Object array) {
247 throw new IllegalStateException();
249 if (to instanceof JSONList) {
250 ((JSONList)to).init(array);
252 JSONList.init(to, array);
256 /** Takes an object representing JSON result and extract some of its
257 * properties. It is assumed that the <code>props</code> and
258 * <code>values</code> arrays have the same length.
260 * @param json the JSON object (actual type depends on the associated
261 * {@link Technology})
262 * @param props list of properties to extract
263 * @param values array that will be filled with extracted values
265 public void extract(Object json, String[] props, Object[] values) {
266 JSON.extract(context, json, props, values);
269 /** Converts raw JSON <code>data</code> into a Java {@link Model} class.
271 * @param <T> type of the model class
272 * @param modelClass the type of the class to create
273 * @param data the raw JSON data
274 * @return newly created instance of the model class
276 public <T> T read(Class<T> modelClass, Object data) {
277 return JSON.read(context, modelClass, data);
280 /** Initializes asynchronous JSON connection to specified URL. Delegates
281 * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
282 * with no extra parameters.
284 * @param index the callback index to be used when a reply is received
285 * to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
287 * @param urlBefore the part of the URL before JSON-P callback parameter
288 * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
289 * @param method method to use for connection to the server
290 * @param data string, number or a {@link Model} generated class to send to
291 * the server when doing a query
293 public void loadJSON(final int index,
294 String urlBefore, String urlAfter, String method,
297 loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
300 /** Initializes asynchronous JSON connection to specified URL. The
301 * method returns immediately and later does callback later.
303 * @param index the callback index to be used when a reply is received
304 * to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
306 * @param urlBefore the part of the URL before JSON-P callback parameter
307 * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
308 * @param method method to use for connection to the server
309 * @param data string, number or a {@link Model} generated class to send to
310 * the server when doing a query
311 * @param params extra params to pass back when calling
312 * {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
315 public void loadJSON(final int index,
316 String urlBefore, String urlAfter, String method,
317 final Object data, final Object... params
319 class Rcvr extends RcvrJSON {
321 protected void onMessage(MsgEvnt msg) {
322 type.onMessage(obj, index, 1, msg.getValues(), params);
326 protected void onError(MsgEvnt msg) {
327 type.onMessage(obj, index, 2, msg.getException(), params);
330 JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
333 /** Opens new WebSocket connection to the specified URL.
335 * @param index the index to use later during callbacks to
336 * {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}
337 * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to
338 * @param data data to send to server (usually <code>null</code>)
339 * @return returns a non-null object representing the socket
340 * which can be used when calling {@link #wsSend(java.lang.Object, java.lang.String, java.lang.Object) }
342 public Object wsOpen(final int index, String url, Object data) {
343 class WSrcvr extends RcvrJSON {
345 protected void onError(MsgEvnt msg) {
346 type.onMessage(obj, index, 2, msg.getException());
350 protected void onMessage(MsgEvnt msg) {
351 type.onMessage(obj, index, 1, msg.getValues());
355 protected void onClose(MsgEvnt msg) {
356 type.onMessage(obj, index, 3, null);
360 protected void onOpen(MsgEvnt msg) {
361 type.onMessage(obj, index, 0, null);
364 return JSON.openWS(context, new WSrcvr(), url, data);
367 /** Sends a message to existing socket.
369 * @param webSocket the socket to send message to
370 * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to,
371 * preferably the same as the one used when the socket was
372 * {@link #wsOpen(int, java.lang.String, java.lang.Object) opened}
373 * @param data the data to send or <code>null</code> if the socket is
374 * supposed to be closed
376 public void wsSend(Object webSocket, String url, Object data) {
377 ((JSON.WS)webSocket).send(context, url, data);
380 /** Converts raw data (one of its properties) to string representation.
382 * @param data the object
383 * @param propName the name of object property or <code>null</code>
384 * if the whole object should be converted
385 * @return the string representation of the object or its property
387 public String toString(Object data, String propName) {
388 return JSON.toString(context, data, propName);
391 /** Converts raw data (one of its properties) to a number representation.
393 * @param data the object
394 * @param propName the name of object property or <code>null</code>
395 * if the whole object should be converted
396 * @return the number representation of the object or its property
398 public Number toNumber(Object data, String propName) {
399 return JSON.toNumber(context, data, propName);
402 /** Converts raw JSON data into a {@link Model} class representation.
404 * @param <T> type of the model to create
405 * @param type class of the model to create
406 * @param data raw JSON data (depends on associated {@link Technology})
407 * @return new instances of the model class filled with values from the
408 * <code>data</code> object
410 public <T> T toModel(Class<T> type, Object data) {
411 return JSON.toModel(context, type, data, null);
414 /** Creates new JSON like observable list.
416 * @param <T> the type of the list elements
417 * @param propName name of a property this list is associated with
418 * @param onChange index of the property to use when the list is modified
419 * during callback to {@link Type#onChange(java.lang.Object, int)}
420 * @param dependingProps the array of {@link ComputedProperty derived properties}
421 * that depend on the value of the list
422 * @return new, empty list associated with this proto-object and its model
424 public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
425 return new JSONList<T>(this, propName, onChange, dependingProps);
428 /** Copies content of one collection to another, re-assigning all its
429 * elements from their current context to the new <code>ctx</code>.
431 * @param <T> type of the collections
432 * @param to the target collection to be filled with cloned values
433 * @param ctx context for the new collection
434 * @param from original collection with its data
436 public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
437 Boolean isModel = null;
439 if (isModel == null) {
440 isModel = JSON.isModel(t.getClass());
443 to.add(JSON.bindTo(t, ctx));
454 final String toStr() {
455 return "Proto[" + obj + "]@" + Integer.toHexString(System.identityHashCode(this));
458 final Bindings initBindings() {
460 Bindings b = Bindings.apply(context, obj);
461 PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
462 for (int i = 0; i < pb.length; i++) {
463 pb[i] = b.registerProperty(
464 type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
467 FunctionBinding[] fb = new FunctionBinding[type.functions.length];
468 for (int i = 0; i < fb.length; i++) {
469 fb[i] = FunctionBinding.registerFunction(
470 type.functions[i], i, obj, type
474 b.finish(obj, pb, fb);
479 final Bindings getBindings() {
483 final void onChange(int index) {
484 type.onChange(obj, index);
487 final Observers observers(boolean create) {
488 if (create && observers == null) {
489 observers = new Observers();
494 /** Functionality used by the code generated by annotation
495 * processor for the {@link net.java.html.json.Model} annotation.
497 * @param <Model> the generated class
500 public static abstract class Type<Model> {
501 private final Class<Model> clazz;
502 private final String[] propertyNames;
503 private final boolean[] propertyReadOnly;
504 private final String[] functions;
506 /** Constructor for subclasses generated by the annotation processor
507 * associated with {@link net.java.html.json.Model} annotation.
509 * @param clazz the generated model class
510 * @param modelFor the original class annotated by the {@link net.java.html.json.Model} annotation.
511 * @param properties number of properties the class has
512 * @param functions number of functions the class has
515 Class<Model> clazz, Class<?> modelFor, int properties, int functions
517 assert getClass().getName().endsWith("$Html4JavaType");
519 assert getClass().getDeclaringClass() == clazz;
520 } catch (SecurityException ex) {
524 this.propertyNames = new String[properties];
525 this.propertyReadOnly = new boolean[properties];
526 this.functions = new String[functions];
527 JSON.register(clazz, this);
530 /** Registers property for the type. It is expected each index
531 * is initialized only once.
533 * @param name name of the property
534 * @param index index of the property
535 * @param readOnly is the property read only?
537 protected final void registerProperty(String name, int index, boolean readOnly) {
538 assert propertyNames[index] == null;
539 propertyNames[index] = name;
540 propertyReadOnly[index] = readOnly;
543 /** Registers function of given name at given index.
545 * @param name name of the function
546 * @param index name of the type
548 protected final void registerFunction(String name, int index) {
549 assert functions[index] == null;
550 functions[index] = name;
553 /** Creates new proto-object for given {@link Model} class bound to
556 * @param obj instance of appropriate {@link Model} class
557 * @param context the browser context
558 * @return new proto-object that the generated class can use for
559 * communication with the infrastructure
561 public Proto createProto(Object obj, BrwsrCtx context) {
562 return new Proto(obj, this, context);
566 // Implemented by subclasses
569 /** Sets value of a {@link #registerProperty(java.lang.String, int, boolean) registered property}
572 * @param model the instance of {@link Model model class}
573 * @param index index of the property used during registration
574 * @param value the value to set the property to
576 protected abstract void setValue(Model model, int index, Object value);
578 /** Obtains and returns value of a
579 * {@link #registerProperty(java.lang.String, int, boolean) registered property}.
581 * @param model the instance of {@link Model model class}
582 * @param index index of the property used during registration
583 * @return current value of the property
585 protected abstract Object getValue(Model model, int index);
587 /** Invokes a {@link #registerFunction(java.lang.String, int)} registered function
590 * @param model the instance of {@link Model model class}
591 * @param index index of the property used during registration
592 * @param data the currently selected object the function is about to operate on
593 * @param event the event that triggered the event
594 * @throws Exception the method can throw exception which is then logged
596 protected abstract void call(Model model, int index, Object data, Object event)
599 /** Re-binds the model object to new browser context.
601 * @param model the instance of {@link Model model class}
602 * @param ctx browser context to clone the object to
603 * @return new instance of the model suitable for new context
605 protected abstract Model cloneTo(Model model, BrwsrCtx ctx);
607 /** Reads raw JSON data and converts them to our model class.
609 * @param c the browser context to work in
610 * @param json raw JSON data to get values from
611 * @return new instance of model class filled by the data
613 protected abstract Model read(BrwsrCtx c, Object json);
615 /** Called when a {@link #registerProperty(java.lang.String, int, boolean) registered property}
618 * @param model the object that has the property
619 * @param index the index of the property during registration
621 protected abstract void onChange(Model model, int index);
623 /** Finds out if there is an associated proto-object for given
626 * @param object an object, presumably (but not necessarily) instance of Model class
627 * @return associated proto-object or <code>null</code>
629 protected abstract Proto protoFor(Object object);
631 /** Called to report results of asynchronous over-the-wire
632 * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
633 * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
635 * @param model the instance of the model class
636 * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
637 * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
638 * not all messages are applicable to all communication protocols (JSON has only 1 and 2).
639 * @param data <code>null</code> or string, number or a {@link Model} class
640 * obtained to the server as a response
642 protected void onMessage(Model model, int index, int type, Object data) {
643 onMessage(model, index, type, data, new Object[0]);
646 /** Called to report results of asynchronous over-the-wire
647 * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
648 * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
650 * @param model the instance of the model class
651 * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
652 * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
653 * not all messages are applicable to all communication protocols (JSON has only 1 and 2).
654 * @param data <code>null</code> or string, number or a {@link Model} class
655 * obtained to the server as a response
656 * @param params extra parameters as passed for example to
657 * {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
661 protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
662 onMessage(model, index, type, data);
666 // Various support methods the generated classes use
669 /** Converts and array of raw JSON objects into an array of typed
670 * Java {@link Model} classes.
672 * @param <T> the type of the destination array
673 * @param context browser context to use
674 * @param src array of raw JSON objects
675 * @param destType type of the individual array elements
676 * @param dest array to be filled with read type instances
678 public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
679 for (int i = 0; i < src.length && i < dest.length; i++) {
680 dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
684 /** Compares two objects that can be converted to integers.
685 * @param a first value
686 * @param b second value
687 * @return true if they are the same
689 public final boolean isSame(int a, int b) {
693 /** Compares two objects that can be converted to (floating point)
695 * @param a first value
696 * @param b second value
697 * @return true if they are the same
699 public final boolean isSame(double a, double b) {
703 /** Compares two objects for being the same - e.g. either <code>==</code>
704 * or <code>equals</code>.
705 * @param a first value
706 * @param b second value
707 * @return true if they are equals
709 public final boolean isSame(Object a, Object b) {
713 if (a == null || b == null) {
719 /** Cumulative hash function. Adds hashcode of the object to the
721 * @param o the object (or <code>null</code>)
722 * @param h the previous value of the hash
723 * @return new hash - the old one xor the object's one
725 public final int hashPlus(Object o, int h) {
726 return o == null ? h : h ^ o.hashCode();
729 /** Converts an object to its JSON value.
731 * @param obj the object to convert
732 * @return JSON representation of the object
734 public final String toJSON(Object obj) {
735 return JSON.toJSON(obj);
738 /** Converts the value to string.
740 * @param val the value
741 * @return the converted value
743 public final String stringValue(Object val) {
744 return JSON.stringValue(val);
747 /** Converts the value to number.
749 * @param val the value
750 * @return the converted value
752 public final Number numberValue(Object val) {
753 return JSON.numberValue(val);
756 /** Converts the value to character.
758 * @param val the value
759 * @return the converted value
761 public final Character charValue(Object val) {
762 return JSON.charValue(val);
765 /** Converts the value to boolean.
767 * @param val the value
768 * @return the converted value
770 public final Boolean boolValue(Object val) {
771 return JSON.boolValue(val);
774 /** Extracts value of specific type from given object.
776 * @param <T> the type of object one is interested in
777 * @param type the type
778 * @param val the object to convert to type
779 * @return the converted value
781 public final <T> T extractValue(Class<T> type, Object val) {
782 if (Number.class.isAssignableFrom(type)) {
783 val = numberValue(val);
785 if (Boolean.class == type) {
786 val = boolValue(val);
788 if (String.class == type) {
789 val = stringValue(val);
791 if (Character.class == type) {
792 val = charValue(val);
794 if (Integer.class == type) {
795 val = val instanceof Number ? ((Number) val).intValue() : 0;
797 if (Long.class == type) {
798 val = val instanceof Number ? ((Number) val).longValue() : 0;
800 if (Short.class == type) {
801 val = val instanceof Number ? ((Number) val).shortValue() : 0;
803 if (Byte.class == type) {
804 val = val instanceof Number ? ((Number) val).byteValue() : 0;
806 if (Double.class == type) {
807 val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
809 if (Float.class == type) {
810 val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
812 if (type.isEnum() && val instanceof String) {
813 val = Enum.valueOf(type.asSubclass(Enum.class), (String)val);
815 return type.cast(val);
818 /** Special dealing with array & {@link List} values. This method
819 * takes the provided collection, empties it and fills it again
820 * with values extracted from <code>value</code> (which is supposed
823 * @param <T> the type of list elements
824 * @param arr collection to fill with elements in value
825 * @param type the type of elements in the collection
826 * @param value array of elements to put into the collecition. If
827 * value is not an array it is wrapped into array with only element
830 public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
832 if (value instanceof Object[]) {
833 newArr = (Object[]) value;
835 newArr = new Object[] { value };
838 for (Object e : newArr) {
839 arr.add(extractValue(type, e));