1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.internal.store

File PropertyConverter.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

24
36
4
1
142
80
20
0.56
9
4
5

Classes

Class Line # Actions
PropertyConverter 51 36 0% 20 13
0.79687579.7%
 

Contributing tests

This file is covered by 9 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.internal.store;
21   
22    import java.util.Arrays;
23    import java.util.List;
24   
25    import javax.inject.Inject;
26    import javax.inject.Singleton;
27   
28    import org.slf4j.Logger;
29    import org.xwiki.component.annotation.Component;
30   
31    import com.xpn.xwiki.objects.BaseProperty;
32    import com.xpn.xwiki.objects.classes.ListClass;
33    import com.xpn.xwiki.objects.classes.NumberClass;
34    import com.xpn.xwiki.objects.classes.PropertyClass;
35   
36    /**
37    * Internal utility class used to convert property values when their type changes. This is useful:
38    * <ul>
39    * <li>when the property value store (e.g. the database table used to store the value) changes as a result of modifying
40    * the property type settings (e.g. switching from single selection to multiple selection)</li>
41    * <li>when the property type changes completely, e.g. by deleting the property and adding a new one with the same name
42    * but with a different type</li>
43    * </ul>
44    * .
45    *
46    * @version $Id: d8a7ea193fce911f39f505e564416d189d895f6b $
47    * @since 7.0M2
48    */
49    @Component(roles = PropertyConverter.class)
50    @Singleton
 
51    public class PropertyConverter
52    {
53    @Inject
54    private Logger logger;
55   
56    /**
57    * Converts the given property to the specified type.
58    *
59    * @param storedProperty the property to convert
60    * @param modifiedPropertyClass the new property type
61    * @return the new (converted) property
62    */
 
63  9 toggle public BaseProperty<?> convertProperty(BaseProperty<?> storedProperty, PropertyClass modifiedPropertyClass)
64    {
65  9 Object newValue = convertPropertyValue(storedProperty.getValue(), modifiedPropertyClass);
66  9 BaseProperty<?> newProperty = null;
67  9 if (newValue != null) {
68  6 newProperty = modifiedPropertyClass.newProperty();
69  6 try {
70    // Try to set the converted value.
71  6 newProperty.setValue(newValue);
72    } catch (Exception e) {
73    // Looks like the conversion didn't succeed. Let's try to compute the value from string.
74    // This should return null if the new value cannot be parsed from string.
75  3 newProperty = modifiedPropertyClass.fromString(storedProperty.toText());
76    }
77  6 if (newProperty != null) {
78  5 newProperty.setId(storedProperty.getId());
79  5 newProperty.setName(storedProperty.getName());
80    } else {
81    // The stored value couldn't be converted to the new property type.
82  1 this.logger.warn("Incompatible data migration when changing field [{}] of class [{}]",
83    modifiedPropertyClass.getName(), modifiedPropertyClass.getClassName());
84    }
85    } else {
86    // If the new value is null then it means the property is not set (it can be removed).
87    }
88  9 return newProperty;
89    }
90   
 
91  9 toggle private Object convertPropertyValue(Object storedValue, PropertyClass modifiedPropertyClass)
92    {
93  9 if (modifiedPropertyClass instanceof ListClass) {
94  4 return convertPropertyValue(storedValue, (ListClass) modifiedPropertyClass);
95  5 } else if (modifiedPropertyClass instanceof NumberClass) {
96  4 return convertPropertyValue(storedValue, (NumberClass) modifiedPropertyClass);
97    } else {
98    // Return the stored value if no specific converter has been found. We will attempt to convert the stored
99    // value through string deserialization later.
100  1 return storedValue;
101    }
102    }
103   
 
104  4 toggle private Object convertPropertyValue(Object storedValue, ListClass modifiedListClass)
105    {
106  4 if (modifiedListClass.isMultiSelect() && !(storedValue instanceof List) && storedValue != null) {
107    // The property has multiple selection so the value must be a list.
108  1 return Arrays.asList(storedValue);
109  3 } else if (!modifiedListClass.isMultiSelect() && storedValue instanceof List) {
110    // The property has single selection so the value must be a string.
111  2 @SuppressWarnings("unchecked")
112    List<String> oldValues = (List<String>) storedValue;
113  2 return oldValues.isEmpty() ? null : oldValues.get(0);
114    }
115    // The stored value doesn't have to be updated.
116  1 return storedValue;
117    }
118   
 
119  4 toggle private Object convertPropertyValue(Object storedValue, NumberClass modifiedNumberClass)
120    {
121  4 Object newValue = storedValue;
122  4 if (storedValue instanceof Number) {
123    // Convert the stored value to the new number type.
124  1 Number storedNumber = (Number) storedValue;
125  1 String newNumberType = modifiedNumberClass.getNumberType();
126  1 if ("integer".equals(newNumberType)) {
127  1 newValue = Integer.valueOf(storedNumber.intValue());
128  0 } else if ("float".equals(newNumberType)) {
129  0 newValue = Float.valueOf(storedNumber.floatValue());
130  0 } else if ("double".equals(newNumberType)) {
131  0 newValue = Double.valueOf(storedNumber.doubleValue());
132  0 } else if ("long".equals(newNumberType)) {
133  0 newValue = Long.valueOf(storedNumber.longValue());
134    }
135    } else {
136    // If we get here then either the stored value is null or the property type has changed. This can happen for
137    // instance if you remove a property and then add a new one with the same name but with a different type. We
138    // return the stored value here but we'll try later to convert it through string deserialization.
139    }
140  4 return newValue;
141    }
142    }