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 }