View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jexl2.internal;
19  import java.util.List;
20  import java.lang.reflect.Array;
21  /**
22   * Specialized executor to set a property in a List or array.
23   * @since 2.0
24   */
25  public final class ListSetExecutor extends AbstractExecutor.Set {
26          /** The java.lang.reflect.Array.get method used as an active marker in ListGet. */
27      private static final java.lang.reflect.Method ARRAY_SET =
28              initMarker(Array.class, "set", Object.class, Integer.TYPE, Object.class);
29      /** The java.util.obj.set method used as an active marker in ListSet. */
30      private static final java.lang.reflect.Method LIST_SET =
31              initMarker(List.class, "set", Integer.TYPE, Object.class);
32      /** The property. */
33      private final Integer property;
34  
35      /**
36       * Creates an instance checking for the List interface or Array capability.
37       * @param is the introspector
38       * @param clazz the class that might implement the map interface
39       * @param key the key to use in obj.set(key,value)
40       * @param value the value to use in obj.set(key,value)
41       */
42      public ListSetExecutor(Introspector is, Class<?> clazz, Integer key, Object value) {
43          super(clazz, discover(clazz));
44          property = key;
45      }
46  
47      /** {@inheritDoc} */
48      @Override
49      public Object getTargetProperty() {
50          return property;
51      }
52      
53      /** {@inheritDoc} */
54      @Override
55      public Object execute(final Object obj, Object value) {
56          if (method == ARRAY_SET) {
57              java.lang.reflect.Array.set(obj, property.intValue(), value);
58          } else {
59              @SuppressWarnings("unchecked") // LSE should only be created for array or list types
60              final List<Object> list = (List<Object>) obj;
61              list.set(property.intValue(), value);
62          }
63          return value;
64      }
65  
66      /** {@inheritDoc} */
67      @Override
68      public Object tryExecute(final Object obj, Object key, Object value) {
69          if (obj != null && method != null
70              && objectClass.equals(obj.getClass())
71              && key instanceof Integer) {
72              if (method == ARRAY_SET) {
73                  Array.set(obj, ((Integer) key).intValue(), value);
74              } else {
75                  @SuppressWarnings("unchecked")  // LSE should only be created for array or list types
76                  final List<Object> list = (List<Object>) obj;
77                  list.set(((Integer) key).intValue(), value);
78              }
79              return value;
80          }
81          return TRY_FAILED;
82      }
83  
84  
85      /**
86       * Finds the method to perform 'set' on a obj of array.
87       * @param clazz the class to introspect
88       * @return a marker method, obj.set or array.set
89       */
90      static java.lang.reflect.Method discover(Class<?> clazz) {
91          if (clazz.isArray()) {
92              // we could verify if the call can be performed but it does not change
93              // the fact we would fail...
94              // Class<?> formal = clazz.getComponentType();
95              // Class<?> actual = value == null? Object.class : value.getClass();
96              // if (IntrospectionUtils.isMethodInvocationConvertible(formal, actual, false)) {
97                  return ARRAY_SET;
98              // }
99          }
100         if (List.class.isAssignableFrom(clazz)) {
101             return LIST_SET;
102         }
103         return null;
104     }
105 }