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 018package org.apache.commons.jexl3.introspection; 019 020import org.apache.commons.jexl3.JexlArithmetic; 021import org.apache.commons.jexl3.JexlOperator; 022 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028 029/** 030 * 'Federated' introspection/reflection interface to allow JEXL introspection 031 * behavior to be customized. 032 * 033 * @since 1.0 034 */ 035public interface JexlUberspect { 036 /** 037 * Abstracts getting property setter and getter. 038 * <p> 039 * These are used through 'strategies' to solve properties; a strategy orders a list of resolver types, 040 * and each resolver type is tried in sequence; the first resolver that discovers a non null {s,g}etter 041 * stops the search. 042 * 043 * @see JexlResolver 044 * @see JexlUberspect#getPropertyGet 045 * @see JexlUberspect#getPropertySet 046 * @since 3.0 047 */ 048 interface PropertyResolver { 049 050 /** 051 * Gets a property getter. 052 * 053 * @param uber the uberspect 054 * @param obj the object 055 * @param identifier the property identifier 056 * @return the property getter or null 057 */ 058 JexlPropertyGet getPropertyGet(JexlUberspect uber, Object obj, Object identifier); 059 060 /** 061 * Gets a property setter. 062 * 063 * @param uber the uberspect 064 * @param obj the object 065 * @param identifier the property identifier 066 * @param arg the property value 067 * @return the property setter or null 068 */ 069 JexlPropertySet getPropertySet(JexlUberspect uber, Object obj, Object identifier, Object arg); 070 } 071 072 /** 073 * The various builtin property resolvers. 074 * <p> 075 * Each resolver discovers how to set/get a property with different techniques; seeking 076 * method names or field names, etc. 077 * 078 * @since 3.0 079 */ 080 enum JexlResolver implements PropertyResolver { 081 /** Seeks methods named get{P,p}property and is{P,p}property. */ 082 PROPERTY, 083 084 /** Seeks map methods get/put. */ 085 MAP, 086 087 /** Seeks list methods get/set. */ 088 LIST, 089 090 /** Seeks any get/{set,put} method (quacking like a list or a map). */ 091 DUCK, 092 093 /** Seeks public instance members.*/ 094 FIELD, 095 096 /** Seeks a getContainer(property) and setContainer(property, value) as in <code>x.container.property</code>. */ 097 CONTAINER; 098 099 @Override 100 public final JexlPropertyGet getPropertyGet(final JexlUberspect uber, 101 final Object obj, 102 final Object identifier) { 103 return uber.getPropertyGet(Collections.singletonList(this), obj, identifier); 104 } 105 106 @Override 107 public final JexlPropertySet getPropertySet(final JexlUberspect uber, 108 final Object obj, 109 final Object identifier, 110 final Object arg) { 111 return uber.getPropertySet(Collections.singletonList(this), obj, identifier, arg); 112 } 113 } 114 115 /** 116 * A resolver types list tailored for POJOs, favors '.' over '[]'. 117 */ 118 List<PropertyResolver> POJO = Collections.unmodifiableList(Arrays.asList( 119 JexlResolver.PROPERTY, 120 JexlResolver.MAP, 121 JexlResolver.LIST, 122 JexlResolver.DUCK, 123 JexlResolver.FIELD, 124 JexlResolver.CONTAINER 125 )); 126 127 /** 128 * A resolver types list tailored for Maps, favors '[]' over '.'. 129 */ 130 List<PropertyResolver> MAP = Collections.unmodifiableList(Arrays.asList( 131 JexlResolver.MAP, 132 JexlResolver.LIST, 133 JexlResolver.DUCK, 134 JexlResolver.PROPERTY, 135 JexlResolver.FIELD, 136 JexlResolver.CONTAINER 137 )); 138 139 /** 140 * Determines property resolution strategy. 141 * 142 * <p>To use a strategy instance, you have to set it at engine creation using 143 * {@link org.apache.commons.jexl3.JexlBuilder#strategy(JexlUberspect.ResolverStrategy)} 144 * as in:</p> 145 * 146 * <code>JexlEngine jexl = new JexlBuilder().strategy(MY_STRATEGY).create();</code> 147 * 148 * @since 3.0 149 */ 150 interface ResolverStrategy { 151 /** 152 * Applies this strategy to a list of resolver types. 153 * 154 * @param operator the property access operator, may be null 155 * @param obj the instance we seek to obtain a property setter/getter from, can not be null 156 * @return the ordered list of resolvers types, must not be null 157 */ 158 List<PropertyResolver> apply(JexlOperator operator, Object obj); 159 } 160 161 /** 162 * The default strategy. 163 * <p> 164 * If the operator is '[]' or if the operator is null and the object is a map, use the MAP list of resolvers; 165 * Other cases use the POJO list of resolvers. 166 */ 167 ResolverStrategy JEXL_STRATEGY = (op, obj) -> { 168 if (op == JexlOperator.ARRAY_GET) { 169 return MAP; 170 } 171 if (op == JexlOperator.ARRAY_SET) { 172 return MAP; 173 } 174 if (op == null && obj instanceof Map) { 175 return MAP; 176 } 177 return POJO; 178 }; 179 180 /** 181 * The map strategy. 182 * 183 * <p>If the operator is '[]' or if the object is a map, use the MAP list of resolvers. 184 * Otherwise, use the POJO list of resolvers.</p> 185 */ 186 ResolverStrategy MAP_STRATEGY = (op, obj) -> { 187 if (op == JexlOperator.ARRAY_GET) { 188 return MAP; 189 } 190 if (op == JexlOperator.ARRAY_SET) { 191 return MAP; 192 } 193 if (obj instanceof Map) { 194 return MAP; 195 } 196 return POJO; 197 }; 198 199 /** 200 * Applies this uberspect property resolver strategy. 201 * 202 * @param op the operator 203 * @param obj the object 204 * @return the applied strategy resolver list 205 */ 206 List<PropertyResolver> getResolvers(JexlOperator op, Object obj); 207 208 /** 209 * Sets the class loader to use. 210 * 211 * <p>This increments the version.</p> 212 * 213 * @param loader the class loader 214 */ 215 void setClassLoader(ClassLoader loader); 216 217 /** 218 * Gets the current class loader. 219 * @return the class loader 220 */ 221 ClassLoader getClassLoader(); 222 223 /** 224 * Gets this uberspect version. 225 * 226 * @return the class loader modification count 227 */ 228 int getVersion(); 229 230 /** 231 * Returns a class constructor. 232 * 233 * @param ctorHandle a class or class name 234 * @param args constructor arguments 235 * @return a {@link JexlMethod} 236 * @since 3.0 237 */ 238 JexlMethod getConstructor(Object ctorHandle, Object... args); 239 240 /** 241 * Returns a JexlMethod. 242 * 243 * @param obj the object 244 * @param method the method name 245 * @param args method arguments 246 * @return a {@link JexlMethod} 247 */ 248 JexlMethod getMethod(Object obj, String method, Object... args); 249 250 /** 251 * Property getter. 252 * 253 * <p>returns a JelPropertySet apropos to an expression like <code>bar.woogie</code>.</p> 254 * 255 * @param obj the object to get the property from 256 * @param identifier property name 257 * @return a {@link JexlPropertyGet} or null 258 */ 259 JexlPropertyGet getPropertyGet(Object obj, Object identifier); 260 261 /** 262 * Property getter. 263 * <p> 264 * Seeks a JexlPropertyGet apropos to an expression like <code>bar.woogie</code>.</p> 265 * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) } 266 * 267 * @param resolvers the list of property resolvers to try 268 * @param obj the object to get the property from 269 * @param identifier property name 270 * @return a {@link JexlPropertyGet} or null 271 * @since 3.0 272 */ 273 JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier); 274 275 /** 276 * Property setter. 277 * <p> 278 * Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p> 279 * 280 * @param obj the object to get the property from. 281 * @param identifier property name 282 * @param arg value to set 283 * @return a {@link JexlPropertySet} or null 284 */ 285 JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg); 286 287 /** 288 * Property setter. 289 * <p> 290 * Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p> 291 * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) } 292 * 293 * @param resolvers the list of property resolvers to try, 294 * @param obj the object to get the property from 295 * @param identifier property name 296 * @param arg value to set 297 * @return a {@link JexlPropertySet} or null 298 * @since 3.0 299 */ 300 JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg); 301 302 /** 303 * Gets an iterator from an object. 304 * 305 * @param obj to get the iterator from 306 * @return an iterator over obj or null 307 */ 308 Iterator<?> getIterator(Object obj); 309 310 /** 311 * Gets an arithmetic operator resolver for a given arithmetic instance. 312 * 313 * @param arithmetic the arithmetic instance 314 * @return the arithmetic uberspect or null if no operator method were overridden 315 * @since 3.0 316 */ 317 JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic); 318 319}