You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datamodel-properties.asciidoc 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. ---
  2. title: Properties
  3. order: 2
  4. layout: page
  5. ---
  6. [[datamodel.properties]]
  7. = Properties
  8. The [interfacename]#Property# interface is the base of the Vaadin Data Model. It
  9. provides a standardized API for a single data value object that can be read
  10. (get) and written (set). A property is always typed, but can optionally support
  11. data type conversions. The type of a property can be any Java class. Optionally,
  12. properties can provide value change events for following their changes.
  13. You can set the value of a property with [methodname]#setValue()# and read with
  14. [methodname]#getValue()#.
  15. In the following, we set and read the property value from a
  16. [classname]#TextField# component, which implements the [interfacename]#Property#
  17. interface to allow accessing the field value.
  18. [source, java]
  19. ----
  20. final TextField tf = new TextField("Name");
  21. // Set the value
  22. tf.setValue("The text field value");
  23. // When the field value is edited by the user
  24. tf.addValueChangeListener(
  25. new Property.ValueChangeListener() {
  26. public void valueChange(ValueChangeEvent event) {
  27. // Do something with the new value
  28. layout.addComponent(new Label(tf.getValue()));
  29. }
  30. });
  31. ----
  32. See the http://demo.vaadin.com/book-examples-vaadin7/book#datamodel.properties.basic[on-line example, window="_blank"].
  33. Changes in the property value usually fire a [classname]#ValueChangeEvent#,
  34. which can be handled with a [classname]#ValueChangeListener#. The event object
  35. provides reference to the property with [methodname]#getProperty()#. Note that
  36. its [methodname]#getValue()# method returns the value with [classname]#Object#
  37. type, so you need to cast it to the proper type.
  38. Properties are in themselves unnamed. They are collected in __items__, which
  39. associate the properties with names: the __Property Identifiers__ or __PID__s.
  40. Items can be further contained in containers and are identified with __Item
  41. Identifiers__ or __IID__s. In the spreadsheet analogy, __Property Identifiers__
  42. would correspond to column names and __Item Identifiers__ to row names. The
  43. identifiers can be arbitrary objects, but must implement the
  44. [methodname]#equals(Object)# and [methodname]#hashCode()# methods so that they
  45. can be used in any standard Java [classname]#Collection#.
  46. The [classname]#Property# interface can be utilized either by implementing the
  47. interface or by using some of the built-in property implementations. Vaadin
  48. includes a [classname]#Property# interface implementation for arbitrary function
  49. pairs and bean properties, with the [classname]#MethodProperty# class, and for
  50. simple object properties, with the [classname]#ObjectProperty# class, as
  51. described later.
  52. In addition to the simple components, selection components provide their current
  53. selection as the property value. In single selection mode, the property is a
  54. single item identifier, while in multiple selection mode it is a set of item
  55. identifiers. See the documentation of the selection components for further
  56. details.
  57. Components that can be bound to a property have an internal default data source
  58. object, typically a [classname]#ObjectProperty#, which is described later. As
  59. all such components are viewers or editors, also described later, so you can
  60. rebind a component to any data source with
  61. [methodname]#setPropertyDataSource()#.
  62. [[datamodel.properties.viewers]]
  63. == Property Viewers and Editors
  64. The most important function of the [classname]#Property# as well as of the other
  65. data model interfaces is to connect classes implementing the interface directly
  66. to editor and viewer classes. This means connecting a data source (model) to a
  67. user interface component (views) to allow editing or viewing the data model.
  68. A property can be bound to a component implementing the [classname]#Viewer#
  69. interface with [methodname]#setPropertyDataSource()#.
  70. [source, java]
  71. ----
  72. // Have a data model
  73. ObjectProperty property =
  74. new ObjectProperty("Hello", String.class);
  75. // Have a component that implements Viewer
  76. Label viewer = new Label();
  77. // Bind it to the data
  78. viewer.setPropertyDataSource(property);
  79. ----
  80. You can use the same method in the [classname]#Editor# interface to bind a
  81. component that allows editing a particular property type to a property.
  82. [source, java]
  83. ----
  84. // Have a data model
  85. ObjectProperty property =
  86. new ObjectProperty("Hello", String.class);
  87. // Have a component that implements Viewer
  88. TextField editor = new TextField("Edit Greeting");
  89. // Bind it to the data
  90. editor.setPropertyDataSource(property);
  91. ----
  92. As all field components implement the [classname]#Property# interface, you can
  93. bind any component implementing the [classname]#Viewer# interface to any field,
  94. assuming that the viewer is able the view the object type of the field.
  95. Continuing from the above example, we can bind a [classname]#Label# to the
  96. [classname]#TextField# value:
  97. [source, java]
  98. ----
  99. Label viewer = new Label();
  100. viewer.setPropertyDataSource(editor);
  101. // The value shown in the viewer is updated immediately
  102. // after editing the value in the editor (once it
  103. // loses the focus)
  104. editor.setImmediate(true);
  105. ----
  106. ifdef::vaadin7[]
  107. If a field has validators, as described in
  108. <<dummy/../../../framework/components/components-fields#components.fields.validation,"Field
  109. Validation">>, the validators are executed before writing the value to the
  110. property data source, or by calling the [methodname]#validate()# or
  111. [methodname]#commit()# for the field.
  112. endif::vaadin7[]
  113. [[datamodel.properties.objectproperty]]
  114. == [classname]#ObjectProperty# Implementation
  115. The [classname]#ObjectProperty# class is a simple implementation of the
  116. [classname]#Property# interface that allows storing an arbitrary Java object.
  117. [source, java]
  118. ----
  119. // Have a component that implements Viewer interface
  120. final TextField tf = new TextField("Name");
  121. // Have a data model with some data
  122. String myObject = "Hello";
  123. // Wrap it in an ObjectProperty
  124. ObjectProperty property =
  125. new ObjectProperty(myObject, String.class);
  126. // Bind the property to the component
  127. tf.setPropertyDataSource(property);
  128. ----
  129. [[datamodel.properties.converter]]
  130. == Converting Between Property Type and Representation
  131. Fields allow editing a certain type, such as a [classname]#String# or
  132. [classname]#Date#. The bound property, on the other hand, could have some
  133. entirely different type. Conversion between a representation edited by the field
  134. and the model defined in the property is handler with a converter that
  135. implements the [interfacename]#Converter# interface.
  136. Most common type conversions, such as between string and integer, are handled by
  137. the default converters. They are created in a converter factory global in the
  138. application.
  139. [[datamodel.properties.converter.basic]]
  140. === Basic Use of Converters
  141. The [methodname]#setConverter([interfacename]#Converter#)# method sets the
  142. converter for a field. The method is defined in [classname]#AbstractField#.
  143. [source, java]
  144. ----
  145. // Have an integer property
  146. final ObjectProperty<Integer> property =
  147. new ObjectProperty<Integer>(42);
  148. // Create a TextField, which edits Strings
  149. final TextField tf = new TextField("Name");
  150. // Use a converter between String and Integer
  151. tf.setConverter(new StringToIntegerConverter());
  152. // And bind the field
  153. tf.setPropertyDataSource(property);
  154. ----
  155. The built-in converters are the following:
  156. [[datamodel.properties.converter.basic.built-in]]
  157. .Built-in Converters
  158. [options="header"]
  159. |===============
  160. |Converter|Representation|Model
  161. |[classname]#StringToIntegerConverter#|[classname]#String#|[classname]#Integer#
  162. |[classname]#StringToDoubleConverter#|[classname]#String#|[classname]#Double#
  163. |[classname]#StringToNumberConverter#|[classname]#String#|[classname]#Number#
  164. |[classname]#StringToBooleanConverter#|[classname]#String#|[classname]#Boolean#
  165. |[classname]#StringToDateConverter#|[classname]#String#|[classname]#Date#
  166. |[classname]#DateToLongConverter#|[classname]#Date#|[classname]#Long#
  167. |===============
  168. In addition, there is a [classname]#ReverseConverter# that takes a converter as
  169. a parameter and reverses the conversion direction.
  170. If a converter already exists for a type, the
  171. [methodname]#setConverter([interfacename]#Class#)# retrieves the converter for
  172. the given type from the converter factory, and then sets it for the field. This
  173. method is used implicitly when binding field to a property data source.
  174. [[datamodel.properties.converter.custom]]
  175. === Implementing a Converter
  176. A conversion always occurs between a __representation type__, edited by the
  177. field component, and a __model type__, that is, the type of the property data
  178. source. Converters implement the [interfacename]#Converter# interface defined in
  179. the [package]#com.vaadin.data.util.converter# package.
  180. For example, let us assume that we have a simple [classname]#Complex# type for
  181. storing complex values.
  182. [source, java]
  183. ----
  184. public class ComplexConverter
  185. implements Converter<String, Complex> {
  186. @Override
  187. public Complex convertToModel(String value, Locale locale)
  188. throws ConversionException {
  189. String parts[] =
  190. value.replaceAll("[\\(\\)]", "").split(",");
  191. if (parts.length != 2)
  192. throw new ConversionException(
  193. "Unable to parse String to Complex");
  194. return new Complex(Double.parseDouble(parts[0]),
  195. Double.parseDouble(parts[1]));
  196. }
  197. @Override
  198. public String convertToPresentation(Complex value,
  199. Locale locale)
  200. throws ConversionException {
  201. return "("+value.getReal()+","+value.getImag()+")";
  202. }
  203. @Override
  204. public Class<Complex> getModelType() {
  205. return Complex.class;
  206. }
  207. @Override
  208. public Class<String> getPresentationType() {
  209. return String.class;
  210. }
  211. }
  212. ----
  213. The conversion methods get the locale for the conversion as a parameter.
  214. [[datamodel.properties.converter.converterfactory]]
  215. === Converter Factory
  216. If a field does not directly allow editing a property type, a default converter
  217. is attempted to create using an application-global converter factory. If you
  218. define your own converters that you wish to include in the converter factory,
  219. you need to implement one yourself. While you could implement the
  220. [interfacename]#ConverterFactory# interface, it is usually easier to just extend
  221. [classname]#DefaultConverterFactory#.
  222. [source, java]
  223. ----
  224. class MyConverterFactory extends DefaultConverterFactory {
  225. @Override
  226. public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL>
  227. createConverter(Class<PRESENTATION> presentationType,
  228. Class<MODEL> modelType) {
  229. // Handle one particular type conversion
  230. if (String.class == presentationType &&
  231. Complex.class == modelType)
  232. return (Converter<PRESENTATION, MODEL>)
  233. new ComplexConverter();
  234. // Default to the supertype
  235. return super.createConverter(presentationType,
  236. modelType);
  237. }
  238. }
  239. // Use the factory globally in the application
  240. Application.getCurrentApplication().setConverterFactory(
  241. new MyConverterFactory());
  242. ----
  243. ifdef::web[]
  244. [[datamodel.properties.implementing]]
  245. == Implementing the [classname]#Property# Interface
  246. Implementation of the [classname]#Property# interface requires defining setters
  247. and getters for the value and the __read-only__ mode. Only a getter is needed
  248. for the property type, as the type is often fixed in property implementations.
  249. The following example shows a simple implementation of the [classname]#Property#
  250. interface:
  251. [source, java]
  252. ----
  253. class MyProperty implements Property {
  254. Integer data = 0;
  255. boolean readOnly = false;
  256. // Return the data type of the model
  257. public Class<?> getType() {
  258. return Integer.class;
  259. }
  260. public Object getValue() {
  261. return data;
  262. }
  263. // Override the default implementation in Object
  264. @Override
  265. public String toString() {
  266. return Integer.toHexString(data);
  267. }
  268. public boolean isReadOnly() {
  269. return readOnly;
  270. }
  271. public void setReadOnly(boolean newStatus) {
  272. readOnly = newStatus;
  273. }
  274. public void setValue(Object newValue)
  275. throws ReadOnlyException, ConversionException {
  276. if (readOnly)
  277. throw new ReadOnlyException();
  278. // Already the same type as the internal representation
  279. if (newValue instanceof Integer)
  280. data = (Integer) newValue;
  281. // Conversion from a string is required
  282. else if (newValue instanceof String)
  283. try {
  284. data = Integer.parseInt((String) newValue, 16);
  285. } catch (NumberFormatException e) {
  286. throw new ConversionException();
  287. }
  288. else
  289. // Don't know how to convert any other types
  290. throw new ConversionException();
  291. // Reverse decode the hexadecimal value
  292. }
  293. }
  294. // Instantiate the property and set its data
  295. MyProperty property = new MyProperty();
  296. property.setValue(42);
  297. // Bind it to a component
  298. final TextField tf = new TextField("Name", property);
  299. ----
  300. The components get the displayed value by the [methodname]#toString()# method,
  301. so it is necessary to override it. To allow editing the value, value returned in
  302. the [methodname]#toString()# must be in a format that is accepted by the
  303. [methodname]#setValue()# method, unless the property is read-only. The
  304. [methodname]#toString()# can perform any type conversion necessary to make the
  305. internal type a string, and the [methodname]#setValue()# must be able to make a
  306. reverse conversion.
  307. The implementation example does not notify about changes in the property value
  308. or in the read-only mode. You should normally also implement at least the
  309. [classname]#Property.ValueChangeNotifier# and
  310. [classname]#Property.ReadOnlyStatusChangeNotifier#. See the
  311. [classname]#ObjectProperty# class for an example of the implementation.
  312. endif::web[]