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 static final 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 /** 129 * A resolver types list tailored for Maps, favors '[]' over '.'. 130 */ 131 static final List<PropertyResolver> MAP = Collections.unmodifiableList(Arrays.asList( 132 JexlResolver.MAP, 133 JexlResolver.LIST, 134 JexlResolver.DUCK, 135 JexlResolver.PROPERTY, 136 JexlResolver.FIELD, 137 JexlResolver.CONTAINER 138 )); 139 140 /** 141 * Determines property resolution strategy. 142 * 143 * <p>To use a strategy instance, you have to set it at engine creation using 144 * {@link org.apache.commons.jexl3.JexlBuilder#strategy(JexlUberspect.ResolverStrategy)} 145 * as in:</p> 146 * 147 * <code>JexlEngine jexl = new JexlBuilder().strategy(MY_STRATEGY).create();</code> 148 * 149 * @since 3.0 150 */ 151 interface ResolverStrategy { 152 /** 153 * Applies this strategy to a list of resolver types. 154 * 155 * @param operator the property access operator, may be null 156 * @param obj the instance we seek to obtain a property setter/getter from, can not be null 157 * @return the ordered list of resolvers types, must not be null 158 */ 159 List<PropertyResolver> apply(JexlOperator operator, Object obj); 160 } 161 162 /** 163 * The default strategy. 164 * <p> 165 * If the operator is '[]' or if the operator is null and the object is a map, use the MAP list of resolvers; 166 * Other cases use the POJO list of resolvers. 167 */ 168 static final ResolverStrategy JEXL_STRATEGY = (op, obj) -> { 169 if (op == JexlOperator.ARRAY_GET) { 170 return MAP; 171 } 172 if (op == JexlOperator.ARRAY_SET) { 173 return MAP; 174 } 175 if (op == null && obj instanceof Map) { 176 return MAP; 177 } 178 return POJO; 179 }; 180 181 /** 182 * The map strategy. 183 * 184 * <p>If the operator is '[]' or if the object is a map, use the MAP list of resolvers. 185 * Otherwise, use the POJO list of resolvers.</p> 186 */ 187 static final ResolverStrategy MAP_STRATEGY = (op, obj) -> { 188 if (op == JexlOperator.ARRAY_GET) { 189 return MAP; 190 } 191 if (op == JexlOperator.ARRAY_SET) { 192 return MAP; 193 } 194 if (obj instanceof Map) { 195 return MAP; 196 } 197 return POJO; 198 }; 199 200 /** 201 * Applies this uberspect property resolver strategy. 202 * 203 * @param op the operator 204 * @param obj the object 205 * @return the applied strategy resolver list 206 */ 207 List<PropertyResolver> getResolvers(JexlOperator op, Object obj); 208 209 /** 210 * Sets the class loader to use. 211 * 212 * <p>This increments the version.</p> 213 * 214 * @param loader the class loader 215 */ 216 void setClassLoader(ClassLoader loader); 217 218 /** 219 * Gets the current class loader. 220 * @return the class loader 221 */ 222 ClassLoader getClassLoader(); 223 224 /** 225 * Gets this uberspect version. 226 * 227 * @return the class loader modification count 228 */ 229 int getVersion(); 230 231 /** 232 * Returns a class constructor. 233 * 234 * @param ctorHandle a class or class name 235 * @param args constructor arguments 236 * @return a {@link JexlMethod} 237 * @since 3.0 238 */ 239 JexlMethod getConstructor(Object ctorHandle, Object... args); 240 241 /** 242 * Returns a JexlMethod. 243 * 244 * @param obj the object 245 * @param method the method name 246 * @param args method arguments 247 * @return a {@link JexlMethod} 248 */ 249 JexlMethod getMethod(Object obj, String method, Object... args); 250 251 /** 252 * Property getter. 253 * 254 * <p>returns a JelPropertySet apropos to an expression like <code>bar.woogie</code>.</p> 255 * 256 * @param obj the object to get the property from 257 * @param identifier property name 258 * @return a {@link JexlPropertyGet} or null 259 */ 260 JexlPropertyGet getPropertyGet(Object obj, Object identifier); 261 262 /** 263 * Property getter. 264 * <p> 265 * Seeks a JexlPropertyGet apropos to an expression like <code>bar.woogie</code>.</p> 266 * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) } 267 * 268 * @param resolvers the list of property resolvers to try 269 * @param obj the object to get the property from 270 * @param identifier property name 271 * @return a {@link JexlPropertyGet} or null 272 * @since 3.0 273 */ 274 JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier); 275 276 /** 277 * Property setter. 278 * <p> 279 * Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p> 280 * 281 * @param obj the object to get the property from. 282 * @param identifier property name 283 * @param arg value to set 284 * @return a {@link JexlPropertySet} or null 285 */ 286 JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg); 287 288 /** 289 * Property setter. 290 * <p> 291 * Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p> 292 * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) } 293 * 294 * @param resolvers the list of property resolvers to try, 295 * @param obj the object to get the property from 296 * @param identifier property name 297 * @param arg value to set 298 * @return a {@link JexlPropertySet} or null 299 * @since 3.0 300 */ 301 JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg); 302 303 /** 304 * Gets an iterator from an object. 305 * 306 * @param obj to get the iterator from 307 * @return an iterator over obj or null 308 */ 309 Iterator<?> getIterator(Object obj); 310 311 /** 312 * Gets an arithmetic operator resolver for a given arithmetic instance. 313 * 314 * @param arithmetic the arithmetic instance 315 * @return the arithmetic uberspect or null if no operator method were overridden 316 * @since 3.0 317 */ 318 JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic); 319 320}