001 /* 002 * Copyright 2004 The Apache Software Foundation 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 package org.apache.commons.convert.conversion; 017 018 import org.apache.commons.convert.Conversion; 019 import org.apache.commons.convert.ConversionFactory; 020 import org.apache.commons.convert.Converter; 021 022 /** 023 * Abstract base class for creating conversion factories. 024 * <p> 025 * This class is especially suited for creating factories as it minimises the effort 026 * required in the subclass. 027 * <p> 028 * To implement a conversion from a class and all of it subclasses, simply extend 029 * this class and implement the {@link #convertValue(Object, Converter)} method. 030 * 031 * @author Stephen Colebourne 032 * @author Oliver Heger 033 * @version $Id: AbstractConversionFactory.java 155441 2005-02-26 13:19:22Z dirkv $ 034 * @since 1.0 035 */ 036 public abstract class AbstractConversionFactory implements ConversionFactory { 037 038 /** Useful constant for subclass constructors */ 039 protected static final Class STRING_CLASS = String.class; 040 041 /** The base type to convert from */ 042 private final Class baseFromType; 043 /** The type to convert to */ 044 private final Class toType; 045 046 /** 047 * Restricted constructor. 048 * 049 * @param baseFromType the base of the class hierarchy to convert from 050 * @param toType the type to convert to 051 */ 052 protected AbstractConversionFactory(Class baseFromType, Class toType) { 053 super(); 054 this.baseFromType = baseFromType; 055 this.toType = toType; 056 } 057 058 //----------------------------------------------------------------------- 059 /** 060 * Checks if this factory matches the request conversion. 061 * <p> 062 * This implementation returns {@link #getMatchPercent()} if the specified 063 * <code>fromType</code> is the same as, or a subclass of, the stored 064 * <code>baseFromType</code> and the specified <code>toType</code> matches 065 * the stored <code>toType</code>. 066 * 067 * @param value the value to be converted, read only, may be null 068 * @param fromType the type to convert from, may be null 069 * @param toType the type to convert to, may be null 070 * @return 60 if baseFromType or subclass matches fromType and toType matches 071 */ 072 public int getMatchPercent(Object value, Class fromType, Class toType) { 073 if (toType == getToType() && getBaseFromType().isAssignableFrom(fromType)) { 074 return getMatchPercent(); 075 } 076 return 0; 077 } 078 079 /** 080 * Gets the percentage to return if a match occurs. 081 * <p> 082 * This implementation returns <code>60</code>. 083 * Subclasses may wish to override and return a different value. 084 * 085 * @return 60 086 */ 087 protected int getMatchPercent() { 088 return 60; 089 } 090 091 /** 092 * Create a new conversion object for the specified from and to types. 093 * <p> 094 * This implementation returns a <code>Conversion</code> instance that 095 * refers back to this class for its implementation of the actual conversion 096 * via {@link #convertValue(Object, Converter)}. 097 * 098 * @param value the value to be converted, read only, may be null 099 * @param fromType the type to convert from, may be null 100 * @param toType the type to convert to, may be null 101 * @return a Conversion object for repeatedly performing conversions 102 */ 103 public Conversion getInstance(Object value, Class fromType, Class toType) { 104 return new FactoryConversion(fromType, toType, this); 105 } 106 107 /** 108 * Convert the non-null value to another type. 109 * <p> 110 * This method is implemented by subclases to perform the actual conversion. 111 * 112 * @param value the input value to be converted, pre-checked to not be null 113 * @param converter the converter being used, not null 114 * @return the converted value 115 * @throws Exception if conversion fails, use ConversionException if creating 116 * a new exception, otherwise just allow exceptions to be thrown 117 */ 118 protected abstract Object convertValue(Object value, Converter converter) throws Exception; 119 120 //----------------------------------------------------------------------- 121 /** 122 * The base type to convert from. 123 * This type and its subclasses will be matched by this factory. 124 * 125 * @return the Class object representing the class to convert to 126 */ 127 public Class getBaseFromType() { 128 return baseFromType; 129 } 130 131 /** 132 * The type to convert to. 133 * 134 * @return the Class object representing the class to convert from 135 */ 136 public Class getToType() { 137 return toType; 138 } 139 140 //----------------------------------------------------------------------- 141 /** 142 * Gets a suitable debugging string. 143 * 144 * @return a debugging string 145 */ 146 public String toString() { 147 String from = convertClassToName(getBaseFromType()); 148 String to = convertClassToName(getToType()); 149 return "ConversionFactory[" + from + "->" + to + "]"; 150 } 151 152 /** 153 * Converts a class to a string name for debugging. 154 * 155 * @param cls the class to convert 156 * @return the class name 157 */ 158 private String convertClassToName(Class cls) { 159 if (cls == null) { 160 return "null"; 161 } 162 String str = cls.getName(); 163 int pos = str.lastIndexOf('.'); 164 if (str.substring(0, pos).equals("java.lang")) { 165 str = str.substring(pos + 1); 166 } 167 if (str.substring(0, pos).equals("java.util")) { 168 str = str.substring(pos + 1); 169 } 170 return str; 171 } 172 173 //----------------------------------------------------------------------- 174 /** 175 * Generic conversion implementation that delegates back to the factory. 176 */ 177 class FactoryConversion extends AbstractConversion { 178 179 /** The factory instance that has the actual conversion code */ 180 private final AbstractConversionFactory factory; 181 182 /** 183 * Constructs a Conversion. 184 * 185 * @param fromType the type to convert from 186 * @param toType the type to convert to 187 * @param factory the factory instance that actually performs the conversion 188 */ 189 FactoryConversion(Class fromType, Class toType, AbstractConversionFactory factory) { 190 super(fromType, toType); 191 this.factory = factory; 192 } 193 194 /** 195 * Convert the non-null value to another type. 196 * <p> 197 * This implementation delegates to the factory method 198 * {@link AbstractConversionFactory#convertValue(Object, Converter)}. 199 * 200 * @param value the input value to be converted, pre-checked to not be null 201 * @param converter the converter being used, not null 202 * @return the converted value 203 * @throws Exception if conversion fails, use ConversionException if creating 204 * a new exception, otherwise just allow exceptions to be thrown 205 */ 206 protected Object convertValue(Object value, Converter converter) throws Exception { 207 return factory.convertValue(value, converter); 208 } 209 } 210 211 }