001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * Granite Data Services is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * Granite Data Services is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 015 * General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 020 * USA, or see <http://www.gnu.org/licenses/>. 021 */ 022package org.granite.messaging.amf.io.convert; 023 024import java.lang.reflect.Constructor; 025import java.lang.reflect.InvocationTargetException; 026import java.lang.reflect.Type; 027import java.lang.reflect.TypeVariable; 028import java.util.ArrayList; 029import java.util.List; 030 031import org.granite.util.TypeUtil; 032 033/** 034 * @author Franck WOLFF 035 * 036 * @see Converter 037 * @see Reverter 038 */ 039public class Converters { 040 041 /** Array of all configured converters */ 042 private Converter[] converters; 043 044 /** Array of all configured reverters */ 045 private Reverter[] reverters; 046 047 /** 048 * Constructs a new Converters instance with the supplied list of converters (possibly reverters). 049 * 050 * @param converterClasses the list of all used converters. 051 * @throws NoSuchMethodException if one of the Converter does not have a constructor with a 052 * Converters parameter. 053 * @throws IllegalAccessException if something goes wrong when creating an instance of one 054 * of the supplied Converter classes. 055 * @throws InvocationTargetException if something goes wrong when creating an instance of one 056 * of the supplied Converter classes. 057 * @throws InstantiationException if something goes wrong when creating an instance of one 058 * of the supplied Converter classes. 059 */ 060 public Converters(List<Class<? extends Converter>> converterClasses) 061 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 062 063 List<Converter> converters = new ArrayList<Converter>(); 064 List<Reverter> reverters = new ArrayList<Reverter>(); 065 066 if (converterClasses != null) { 067 for (Class<? extends Converter> converterClass : converterClasses) { 068 Constructor<? extends Converter> constructor = converterClass.getConstructor(Converters.class); 069 Converter converter = constructor.newInstance(this); 070 converters.add(converter); 071 if (converter instanceof Reverter) 072 reverters.add((Reverter)converter); 073 } 074 } 075 076 this.converters = converters.toArray(new Converter[converters.size()]); 077 this.reverters = reverters.toArray(new Reverter[reverters.size()]); 078 } 079 080 public void addConverter(Class<? extends Converter> converterClass) 081 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 082 083 Converter[] converters = new Converter[this.converters.length+1]; 084 System.arraycopy(this.converters, 0, converters, 1, this.converters.length); 085 Constructor<? extends Converter> constructor = converterClass.getConstructor(Converters.class); 086 converters[0] = constructor.newInstance(this); 087 this.converters = converters; 088 089 if (converters[0] instanceof Reverter) { 090 Reverter[] reverters = new Reverter[this.reverters.length+1]; 091 System.arraycopy(this.reverters, 0, reverters, 1, this.reverters.length); 092 reverters[0] = (Reverter)converters[0]; 093 this.reverters = reverters; 094 } 095 } 096 097 /** 098 * Returns a suitable converter for supplied parameters or null if no converter 099 * can be found. This method is equivalent to the 100 * {@link Converters#getConverter(Object, Type, boolean)} method with the 101 * throwNotFoundException parameter set to false. 102 * 103 * @param value the value to be converted 104 * @param targetType the type of the converted value 105 * @return a Converter instance or null if no suitable converter can be found 106 */ 107 public Converter getConverter(Object value, Type targetType) { 108 return getConverter(value, targetType, false); 109 } 110 111 /** 112 * Returns a suitable converter for supplied parameters or either returns null if no converter 113 * can be found or throws a {@link NoConverterFoundException}. 114 * 115 * @param value the value to be converted 116 * @param targetType the type of the converted value 117 * @param throwNotFoundException should an exception be thrown if no converter is found? 118 * @return a Converter instance or null if no suitable converter can be found 119 * @throws NoConverterFoundException if the throwNotFoundException parameter is set to true 120 * and no converter can be found. 121 */ 122 public Converter getConverter(Object value, Type targetType, boolean throwNotFoundException) 123 throws NoConverterFoundException { 124 125 // Small optimization: this avoids to make TypeVariable conversion in all converters... 126 if (targetType instanceof TypeVariable<?>) 127 targetType = TypeUtil.getBoundType((TypeVariable<?>)targetType); 128 129 for (Converter converter : converters) { 130 if (converter.canConvert(value, targetType)) 131 return converter; 132 } 133 134 if (!throwNotFoundException) 135 return null; 136 137 throw new NoConverterFoundException(value, targetType); 138 } 139 140 /** 141 * Converts the supplied object to the supplied target type. This method is 142 * a simple shortcut for: <tt>this.getConverter(value, target, true).convert(value, targetType)</tt>. 143 * 144 * @param value the object to be converted. 145 * @param targetType the target type. 146 * @return the converted object. 147 * @throws NoConverterFoundException if no suitable converter can be found. 148 */ 149 public Object convert(Object value, Type targetType) throws NoConverterFoundException { 150 return getConverter(value, targetType, true).convert(value, targetType); 151 } 152 153 /** 154 * Returns true if at least one reverter is configured for this Converters instance. 155 * 156 * @return true if at least one reverter is configured for this Converters instance. 157 */ 158 public boolean hasReverters() { 159 return reverters.length > 0; 160 } 161 162 /** 163 * Revert back to standard, AMF3 known Java type the supplied value. This method iterates 164 * on all configured Reverters and returns the {@link Reverter#revert(Object)} method result 165 * if the {@link Reverter#canRevert(Object)} method returns true for the current Reverter 166 * instance. 167 * 168 * @param value the value to be reverted. 169 * @return the reverted value (same instance if none of the configured reverters apply). 170 */ 171 public Object revert(Object value) { 172 for (Reverter reverter : reverters) { 173 if (reverter.canRevert(value)) 174 return reverter.revert(value); 175 } 176 return value; 177 } 178 179 public Converter[] getConverters() { 180 Converter[] copy = new Converter[converters.length]; 181 System.arraycopy(converters, 0, copy, 0, converters.length); 182 return copy; 183 } 184}