001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Jean-Marc Orliaguet, Chalmers 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.theme.properties; 023 024import java.io.IOException; 025import java.lang.reflect.Field; 026import java.lang.reflect.ParameterizedType; 027import java.lang.reflect.Type; 028import java.util.ArrayList; 029import java.util.Collection; 030import java.util.Enumeration; 031import java.util.List; 032import java.util.Properties; 033 034import org.nuxeo.theme.Utils; 035import org.nuxeo.theme.themes.ThemeIOException; 036 037public class FieldIO { 038 039 public static FieldInfo getFieldInfo(Class<?> c, String name) { 040 try { 041 return c.getField(name).getAnnotation(FieldInfo.class); 042 } catch (SecurityException e) { 043 return null; 044 } catch (NoSuchFieldException e) { 045 return null; 046 } 047 } 048 049 public static void updateFieldsFromProperties(Object object, Properties properties) throws ThemeIOException { 050 Enumeration<?> names = properties.propertyNames(); 051 052 while (names.hasMoreElements()) { 053 String name = (String) names.nextElement(); 054 String value = properties.getProperty(name); 055 056 Class<?> c = object.getClass(); 057 058 FieldInfo fieldInfo = getFieldInfo(c, name); 059 if (fieldInfo == null) { 060 continue; 061 } 062 063 Field field; 064 try { 065 field = c.getField(name); 066 } catch (SecurityException e) { 067 throw new ThemeIOException(e); 068 } catch (NoSuchFieldException e) { 069 throw new ThemeIOException("Failed to set field '" + name + "' on " + c.getCanonicalName()); 070 } 071 072 Class<?> fieldType = field.getType(); 073 Type fieldGenericType = field.getGenericType(); 074 075 // boolean fields 076 if (fieldType.equals(boolean.class) || fieldType.equals(Boolean.class)) { 077 try { 078 field.set(object, Boolean.parseBoolean(value)); 079 } catch (IllegalArgumentException e) { 080 throw new ThemeIOException(e); 081 } catch (IllegalAccessException e) { 082 throw new ThemeIOException(e); 083 } 084 } 085 086 // string fields 087 else if (fieldType.equals(String.class)) { 088 try { 089 field.set(object, value); 090 } catch (IllegalArgumentException e) { 091 throw new ThemeIOException(e); 092 } catch (IllegalAccessException e) { 093 throw new ThemeIOException(e); 094 } 095 } 096 097 // integer fields 098 else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) { 099 try { 100 if ("".equals(value)) { 101 field.set(object, null); 102 } else { 103 field.set(object, Integer.valueOf(value)); 104 } 105 } catch (NumberFormatException e) { 106 throw new ThemeIOException("Failed to parse integer value: '" + value + "'"); 107 } catch (IllegalArgumentException e) { 108 throw new ThemeIOException(e); 109 } catch (IllegalAccessException e) { 110 throw new ThemeIOException(e); 111 } 112 } 113 114 // generics 115 else if (fieldGenericType instanceof ParameterizedType) { 116 if (fieldType.equals(ArrayList.class) || fieldType.equals(List.class) 117 || fieldType.equals(Collection.class)) { 118 119 Type[] actualTypes = ((ParameterizedType) fieldGenericType).getActualTypeArguments(); 120 121 if (actualTypes.length > 1) { 122 throw new ThemeIOException("Only one-dimension arrays are supported."); 123 } 124 125 // Collection<String> 126 if (actualTypes[0].equals(String.class)) { 127 List<String> list = new ArrayList<String>(); 128 try { 129 list = Utils.csvToList(value); 130 } catch (IOException e) { 131 throw new ThemeIOException(e); 132 } 133 try { 134 field.set(object, list); 135 } catch (IllegalArgumentException e) { 136 throw new ThemeIOException(e); 137 } catch (IllegalAccessException e) { 138 throw new ThemeIOException(e); 139 } 140 } 141 } 142 } else { 143 throw new ThemeIOException("Cannot update field type '" + name + "' of " + c.getCanonicalName() 144 + " because " + fieldType.getCanonicalName() + " is not supported."); 145 } 146 } 147 148 } 149 150 @SuppressWarnings("unchecked") 151 public static Properties dumpFieldsToProperties(Object object) throws ThemeIOException { 152 153 Properties properties = new Properties(); 154 155 Class<?> c = object.getClass(); 156 for (Field field : c.getDeclaredFields()) { 157 Class<?> fieldType = field.getType(); 158 Type fieldGenericType = field.getGenericType(); 159 String fieldName = field.getName(); 160 161 FieldInfo fieldInfo = getFieldInfo(c, fieldName); 162 if (fieldInfo == null) { 163 continue; 164 } 165 166 String property = ""; 167 Object value; 168 try { 169 value = field.get(object); 170 } catch (IllegalAccessException e) { 171 throw new ThemeIOException(e); 172 } catch (IllegalArgumentException e) { 173 throw new ThemeIOException(e); 174 } 175 176 // boolean fields 177 if (fieldType.equals(boolean.class) || fieldType.equals(Boolean.class)) { 178 if (value == null) { 179 property = "false"; 180 } else { 181 property = Boolean.parseBoolean(value.toString()) ? "true" : "false"; 182 } 183 } 184 // string fields 185 else if (fieldType.equals(String.class)) { 186 property = value == null ? "" : value.toString(); 187 } 188 // integer fields 189 else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) { 190 property = value == null ? "" : value.toString(); 191 } 192 // generics 193 else if (fieldGenericType instanceof ParameterizedType) { 194 if (fieldType.equals(ArrayList.class) || fieldType.equals(List.class) 195 || fieldType.equals(Collection.class)) { 196 197 Type[] actualTypes = ((ParameterizedType) fieldGenericType).getActualTypeArguments(); 198 199 if (actualTypes.length > 1) { 200 throw new ThemeIOException("Only one-dimension arrays are supported."); 201 } 202 203 // Collection<String> 204 if (actualTypes[0].equals(String.class)) { 205 if (value == null) { 206 property = ""; 207 } else { 208 property = Utils.listToCsv((List<String>) (value)); 209 } 210 } else { 211 throw new ThemeIOException("Only list of strings are supported."); 212 } 213 214 } 215 } else { 216 throw new ThemeIOException("Cannot extract property from field type '" + fieldName + "' of " 217 + c.getCanonicalName() + " because " + fieldType.getCanonicalName() + " is not supported."); 218 } 219 220 properties.setProperty(fieldName, property); 221 222 } 223 return properties; 224 } 225}