| ////////////////////// |
| * Copyright (c) 2007-2012, Niclas Hedhman. All Rights Reserved. |
| * Copyright (c) 2013, Paul Merlin. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, |
| * either express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| ////////////////////// |
| |
| [[core-api-value,ValueComposite]] |
| = ValueComposite = |
| Usage of value objects is one of the most ignored and best return-on-investment the programmer can do. Values are |
| immutable and can be compared by value instead of memory reference. Concurrency is suddenly not an issue, since either |
| the value exists or it doesn't, no need for synchronization. Values are typically very easy to test and very robust to |
| refactoring. |
| |
| Zestâ„¢ defines values as a primary meta type through the ValueComposite, as we think the benefits of values are great. |
| The ValueComposite is very light-weight compared to the EntityComposite, and its value can still be persisted as part |
| of an EntityComposite via a Property. |
| |
| The characteristics of a ValueComposite compared to other Composite meta types are; |
| |
| * It is Immutable. |
| * Its equals/hashCode works on both the descriptor and the values of the ValueComposite. |
| * Can be used as Property types. |
| * Can be serialized and deserialized. |
| |
| == Value Serialization == |
| Value objects can be serialized and deserialized using the ValueSerialization API which is a Service API implemented |
| by SPI and extensions. |
| |
| TIP: +ValueSerialization extends ValueSerializer, ValueDeserializer+. See the <<javadocs>> for interfaces detail. |
| |
| The ValueSerialization mechanism apply to the following object types : |
| |
| * ValueComposite, |
| * EntityReference, |
| * Iterable, |
| * Map, |
| * Plain Value. |
| |
| Nested Plain Values, EntityReferences, Iterables, Maps, ValueComposites are supported. |
| EntityComposites and EntityReferences are serialized as their identity string. |
| |
| Plain Values can be one of : |
| |
| * String, |
| * Character or char, |
| * Boolean or boolean, |
| * Integer or int, |
| * Long or long, |
| * Short or short, |
| * Byte or byte, |
| * Float or float, |
| * Double or double, |
| * BigInteger, |
| * BigDecimal, |
| * Date, |
| * DateTime (JodaTime), |
| * LocalDateTime (JodaTime), |
| * LocalDate (JodaTime). |
| |
| TIP: Serialization behaviour can be tuned with options. |
| Every +ValueSerializer+ methods can take a +ValueSerializer.Options+ object that contains flags to change how some |
| values are serialized. See the <<javadocs>> for more details. |
| |
| Values of unknown types and all arrays are considered as +java.io.Serializable+ and by so are (de)serialized to (from) |
| base64 encoded bytes using pure Java serialization. If it happens that the value is not Serializable or the input to |
| deserialize is invalid, a +ValueSerializationException+ is thrown. |
| |
| Methods of +ValueSerializer+ allow to specify if the serialized state should contain extra type information about the |
| serialized value. Having type information in the serialized payload allows to keep actual ValueComposite types and by so |
| circumvent +AmbiguousTypeException+ when deserializing. |
| |
| Core Runtime provides a default ValueSerialization system based on the |
| https://github.com/douglascrockford/JSON-java[org.json] Java library producing and consuming JSON. |
| |
| Let's see how it works in practice. |
| |
| [snippet,java] |
| ---- |
| source=core/api/src/test/java/org/qi4j/api/value/DocumentationSupport.java |
| tag=default |
| ---- |
| |
| Reading this first example step by step we ; |
| |
| . declare a ValueComposite, |
| . assemble it, |
| . create a new Value instance, |
| . use the +ValueComposite#toString()+ method to get a JSON representation of the Value, |
| . and finally, use the +Module#newValueFromSerializedState()+ method to create a new Value instance from the JSON |
| state. |
| |
| +ValueComposite#toString()+ method leverage Value Serialization and by so provide JSON based representation. The Module |
| API allows to create new Value instances from serialized state. |
| |
| On top of that, Application assemblies can register different implementation of ValueSerialization as Services to |
| support more formats, see the <<extensions>> section. Note that the default behaviour described above is overriden if a |
| ValueSerialization Service is visible. |
| |
| Let's see how to use the ValueSerialization Services. |
| |
| [snippet,java] |
| ---- |
| source=core/api/src/test/java/org/qi4j/api/value/DocumentationSupport.java |
| tag=service |
| ---- |
| |
| In this second example, we ; |
| |
| . declare a ValueComposite, |
| . assemble it, |
| . assemble a ValueSerialization Service backed by the +org.json+ package, |
| . get the +ValueSerializer+ and +ValueDeserializer+ Services injected, |
| . create a new Value instance, |
| . use the +ValueSerializer#serialize()+ method to get a JSON representation of the Value, |
| . and finally, use the +ValueDeserializer#eserialize()+ method to create a new Value instance from the JSON state. |
| |
| Many applications need to stream data. The ValueSerialization API support such use cases in two ways. |
| |
| The first one use classic streams. |
| |
| [snippet,java] |
| ---- |
| source=core/api/src/test/java/org/qi4j/api/value/DocumentationSupport.java |
| tag=stream |
| ---- |
| |
| . get a handle on a source of values and an +OutputStream+, |
| . serialize data into the +OutputStream+, |
| . get a handle on an +InputStream+, |
| . deserialize data from the +InputStream+. |
| |
| The second one use the <<core-io>>: |
| |
| [snippet,java] |
| ---- |
| source=core/api/src/test/java/org/qi4j/api/value/DocumentationSupport.java |
| tag=io |
| ---- |
| |
| . get a handle on a source of values and a +Writer+, |
| . prepare the serialization +Function+, |
| . serialize a collection of values, one serialized value per line, |
| . get a handle on a serialized values +Reader+ and create a new empty +List+ of values, |
| . prepare the deserialization +Function+, |
| . deserialize a collection of values from read lines. |
| |