001 package org.apache.commons.ognl; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.lang.reflect.Array; 023 import java.util.Map; 024 025 /** 026 * Implementation of PropertyAccessor that uses numbers and dynamic subscripts as properties to index into Java arrays. 027 * 028 * @author Luke Blanshard (blanshlu@netscape.net) 029 * @author Drew Davidson (drew@ognl.org) 030 */ 031 public class ArrayPropertyAccessor 032 extends ObjectPropertyAccessor 033 implements PropertyAccessor 034 { 035 036 @Override 037 public Object getProperty( Map<String, Object> context, Object target, Object name ) 038 throws OgnlException 039 { 040 Object result = null; 041 042 if ( name instanceof String ) 043 { 044 if ( "length".equals( name ) ) 045 { 046 result = Array.getLength( target ); 047 } 048 else 049 { 050 result = super.getProperty( context, target, name ); 051 } 052 } 053 else 054 { 055 Object index = name; 056 057 if ( index instanceof DynamicSubscript ) 058 { 059 int len = Array.getLength( target ); 060 061 switch ( ( (DynamicSubscript) index ).getFlag() ) 062 { 063 case DynamicSubscript.ALL: 064 result = Array.newInstance( target.getClass().getComponentType(), len ); 065 System.arraycopy( target, 0, result, 0, len ); 066 break; 067 case DynamicSubscript.FIRST: 068 index = ( len > 0 ) ? 0 : -1; 069 break; 070 case DynamicSubscript.MID: 071 index = ( len > 0 ) ? ( len / 2 ) : -1; 072 break; 073 case DynamicSubscript.LAST: 074 index = ( len > 0 ) ? ( len - 1 ) : -1; 075 break; 076 default: break; 077 } 078 } 079 if ( result == null ) 080 { 081 if ( index instanceof Number ) 082 { 083 int i = ( (Number) index ).intValue(); 084 085 result = ( i >= 0 ) ? Array.get( target, i ) : null; 086 } 087 else 088 { 089 throw new NoSuchPropertyException( target, index ); 090 } 091 } 092 } 093 return result; 094 } 095 096 @Override 097 public void setProperty( Map<String, Object> context, Object target, Object name, Object value ) 098 throws OgnlException 099 { 100 boolean isNumber = ( name instanceof Number ); 101 102 if ( isNumber || ( name instanceof DynamicSubscript ) ) 103 { 104 TypeConverter converter = ( (OgnlContext) context ).getTypeConverter(); 105 Object convertedValue; 106 107 convertedValue = converter.convertValue( context, target, null, name.toString(), value, 108 target.getClass().getComponentType() ); 109 if ( isNumber ) 110 { 111 int i = ( (Number) name ).intValue(); 112 113 if ( i >= 0 ) 114 { 115 Array.set( target, i, convertedValue ); 116 } 117 } 118 else 119 { 120 int len = Array.getLength( target ); 121 122 switch ( ( (DynamicSubscript) name ).getFlag() ) 123 { 124 case DynamicSubscript.ALL: 125 System.arraycopy( target, 0, convertedValue, 0, len ); 126 return; 127 default: 128 break; 129 } 130 } 131 } 132 else 133 { 134 if ( name instanceof String ) 135 { 136 super.setProperty( context, target, name, value ); 137 } 138 else 139 { 140 throw new NoSuchPropertyException( target, name ); 141 } 142 } 143 } 144 145 @Override 146 public String getSourceAccessor( OgnlContext context, Object target, Object index ) 147 { 148 String indexStr = getIndexString( context, index ); 149 150 context.setCurrentAccessor( target.getClass() ); 151 context.setCurrentType( target.getClass().getComponentType() ); 152 153 return "[" + indexStr + "]"; 154 } 155 156 @Override 157 public String getSourceSetter( OgnlContext context, Object target, Object index ) 158 { 159 String indexStr = getIndexString( context, index ); 160 161 Class<?> type = target.getClass().isArray() ? target.getClass().getComponentType() : target.getClass(); 162 163 context.setCurrentAccessor( target.getClass() ); 164 context.setCurrentType( target.getClass().getComponentType() ); 165 166 if ( type.isPrimitive() ) 167 { 168 Class<?> wrapClass = OgnlRuntime.getPrimitiveWrapperClass( type ); 169 170 return "[" + indexStr + "]=((" + wrapClass.getName() + ")org.apache.commons.ognl.OgnlOps.convertValue($3," 171 + wrapClass.getName() + ".class, true))." + OgnlRuntime.getNumericValueGetter( wrapClass ); 172 } 173 return "[" + indexStr + "]=org.apache.commons.ognl.OgnlOps.convertValue($3," + type.getName() + ".class)"; 174 } 175 176 private static String getIndexString( OgnlContext context, Object index ) 177 { 178 String indexStr = index.toString(); 179 180 // need to convert to primitive for list index access 181 182 // System.out.println("index class " + index.getClass() + " current type " + context.getCurrentType() + 183 // " current object class " + context.getCurrentObject().getClass()); 184 185 if ( context.getCurrentType() != null && !context.getCurrentType().isPrimitive() 186 && Number.class.isAssignableFrom( context.getCurrentType() ) ) 187 { 188 indexStr += "." + OgnlRuntime.getNumericValueGetter( context.getCurrentType() ); 189 } 190 else if ( context.getCurrentObject() != null && Number.class.isAssignableFrom( 191 context.getCurrentObject().getClass() ) && !context.getCurrentType().isPrimitive() ) 192 { 193 // means it needs to be cast first as well 194 195 String toString = 196 String.class.isInstance( index ) && context.getCurrentType() != Object.class ? "" : ".toString()"; 197 198 indexStr = "org.apache.commons.ognl.OgnlOps#getIntValue(" + indexStr + toString + ")"; 199 } 200 return indexStr; 201 } 202 }