View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.Array;
23  import java.util.Map;
24  
25  /**
26   * Implementation of PropertyAccessor that uses numbers and dynamic subscripts as properties to index into Java arrays.
27   * 
28   * @author Luke Blanshard (blanshlu@netscape.net)
29   * @author Drew Davidson (drew@ognl.org)
30   */
31  public class ArrayPropertyAccessor
32      extends ObjectPropertyAccessor
33      implements PropertyAccessor
34  {
35  
36      @Override
37      public Object getProperty( Map<String, Object> context, Object target, Object name )
38          throws OgnlException
39      {
40          Object result = null;
41  
42          if ( name instanceof String )
43          {
44              if ( "length".equals( name ) )
45              {
46                  result = Array.getLength( target );
47              }
48              else
49              {
50                  result = super.getProperty( context, target, name );
51              }
52          }
53          else
54          {
55              Object index = name;
56  
57              if ( index instanceof DynamicSubscript )
58              {
59                  int len = Array.getLength( target );
60  
61                  switch ( ( (DynamicSubscript) index ).getFlag() )
62                  {
63                      case DynamicSubscript.ALL:
64                          result = Array.newInstance( target.getClass().getComponentType(), len );
65                          System.arraycopy( target, 0, result, 0, len );
66                          break;
67                      case DynamicSubscript.FIRST:
68                          index = ( len > 0 ) ? 0 : -1;
69                          break;
70                      case DynamicSubscript.MID:
71                          index = ( len > 0 ) ? ( len / 2 ) : -1;
72                          break;
73                      case DynamicSubscript.LAST:
74                          index = ( len > 0 ) ? ( len - 1 ) : -1;
75                          break;
76                      default: break;
77                  }
78              }
79              if ( result == null )
80              {
81                  if ( index instanceof Number )
82                  {
83                      int i = ( (Number) index ).intValue();
84  
85                      result = ( i >= 0 ) ? Array.get( target, i ) : null;
86                  }
87                  else
88                  {
89                      throw new NoSuchPropertyException( target, index );
90                  }
91              }
92          }
93          return result;
94      }
95  
96      @Override
97      public void setProperty( Map<String, Object> context, Object target, Object name, Object value )
98          throws OgnlException
99      {
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 }