001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.betwixt.expression; 018 019 import java.lang.reflect.Array; 020 import java.util.Collection; 021 022 import org.apache.commons.logging.Log; 023 import org.apache.commons.logging.LogFactory; 024 025 /** 026 * Abstracts common features for strongly typed <code>Updater</code>'s. 027 * Strongly type <code>Updater</code>'s perform conversions based on this 028 * the expected type before the bean update is invoked. 029 * @since 0.7 030 * @author <a href='http://commons.apache.org'>Apache Commons Team</a>, <a href='http://www.apache.org'>Apache Software Foundation</a> 031 */ 032 public abstract class TypedUpdater implements Updater { 033 034 /** Logger */ 035 private static final Log log = LogFactory.getLog( TypedUpdater.class ); 036 037 038 /** The type of the first parameter of the method */ 039 private Class valueType; 040 041 /** 042 * Updates the current bean context with the given String value 043 * @param context the Context to be updated 044 * @param newValue the update to this new value 045 */ 046 public void update(Context context, Object newValue) { 047 Object bean = context.getBean(); 048 if ( bean != null ) { 049 if ( newValue instanceof String ) { 050 // try to convert into primitive types 051 if ( log.isTraceEnabled() ) { 052 log.trace("Converting primitive to " + valueType); 053 } 054 newValue = context.getObjectStringConverter() 055 .stringToObject( (String) newValue, valueType, context ); 056 } 057 if ( newValue != null ) { 058 // check that it is of the correct type 059 /* 060 if ( ! valueType.isAssignableFrom( newValue.getClass() ) ) { 061 log.warn( 062 "Cannot call setter method: " + method.getName() + " on bean: " + bean 063 + " with type: " + bean.getClass().getName() 064 + " as parameter should be of type: " + valueType.getName() 065 + " but is: " + newValue.getClass().getName() 066 ); 067 return; 068 } 069 */ 070 } 071 // special case for collection objects into arrays 072 if (newValue instanceof Collection && valueType.isArray()) { 073 Collection valuesAsCollection = (Collection) newValue; 074 Class componentType = valueType.getComponentType(); 075 if (componentType != null) { 076 Object[] valuesAsArray = 077 (Object[]) Array.newInstance(componentType, valuesAsCollection.size()); 078 newValue = valuesAsCollection.toArray(valuesAsArray); 079 } 080 } 081 082 ; 083 try { 084 executeUpdate( context, bean, newValue ); 085 086 } catch (Exception e) { 087 String valueTypeName = (newValue != null) ? newValue.getClass().getName() : "null"; 088 log.warn( 089 "Cannot evaluate: " + this.toString() + " on bean: " + bean 090 + " of type: " + bean.getClass().getName() + " with value: " + newValue 091 + " of type: " + valueTypeName 092 ); 093 handleException(context, e); 094 } 095 } 096 } 097 098 099 100 /** 101 * Gets the type expected. 102 * The value passed into {@link #update} 103 * will be converted on the basis of this type 104 * before being passed to {@link #executeUpdate}. 105 * @return <code>Class</code> giving expected type, not null 106 */ 107 public Class getValueType() { 108 return valueType; 109 } 110 111 /** 112 * Sets the type expected. 113 * The value passed into {@link #update} 114 * will be converted on the basis of this type 115 * before being passed to {@link #executeUpdate}. 116 * @param valueType <code>Class</code> giving expected type, not null 117 */ 118 public void setValueType(Class valueType) { 119 this.valueType = valueType; 120 } 121 122 /** 123 * Updates the bean with the given value. 124 * @param bean 125 * @param value value after type conversion 126 */ 127 protected abstract void executeUpdate(Context context, Object bean, Object value) throws Exception; 128 129 /** 130 * Strategy method to allow derivations to handle exceptions differently. 131 * @param context the Context being updated when this exception occured 132 * @param e the Exception that occured during the update 133 */ 134 protected void handleException(Context context, Exception e) { 135 log.info( "Caught exception: " + e, e ); 136 } 137 138 }