private List<PropertyAccessor> initPropertyAccessors() { List<PropertyAccessor> accessors = this.propertyAccessors; if (accessors == null) { accessors = new ArrayList<>(5); accessors.add(new ReflectivePropertyAccessor()); this.propertyAccessors = accessors; } return accessors; }
@Nullable private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) { Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass()); if (type.isArray() && name.equals("length")) { return TypeDescriptor.valueOf(Integer.TYPE); } PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey); if (typeDescriptor == null) { // Attempt to populate the cache entry try { if (canRead(context, target, name) || canWrite(context, target, name)) { typeDescriptor = this.typeDescriptorCache.get(cacheKey); } } catch (AccessException ex) { // Continue with null type descriptor } } return typeDescriptor; }
Method method = findGetterForProperty(name, type, target); if (method != null) { Field field = findField(name, type, target); if (field != null) { TypeDescriptor typeDescriptor = new TypeDescriptor(field);
/** * Find a getter method for the specified property. */ @Nullable protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) { Method method = findMethodForProperty(getPropertyMethodSuffixes(propertyName), "get", clazz, mustBeStatic, 0, ANY_TYPES); if (method == null) { method = findMethodForProperty(getPropertyMethodSuffixes(propertyName), "is", clazz, mustBeStatic, 0, BOOLEAN_TYPES); } return method; }
@Override public boolean canWrite(EvaluationContext context, @Nullable Object target, String name) throws AccessException { if (!this.allowWrite || target == null) { return false; } Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass()); PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); if (this.writerCache.containsKey(cacheKey)) { return true; } Method method = findSetterForProperty(name, type, target); if (method != null) { // Treat it like a property Property property = new Property(type, null, method); TypeDescriptor typeDescriptor = new TypeDescriptor(property); this.writerCache.put(cacheKey, method); this.typeDescriptorCache.put(cacheKey, typeDescriptor); return true; } else { Field field = findField(name, type, target); if (field != null) { this.writerCache.put(cacheKey, field); this.typeDescriptorCache.put(cacheKey, new TypeDescriptor(field)); return true; } } return false; }
@Test public void testReflectivePropertyAccessor() throws Exception { ReflectivePropertyAccessor rpa = new ReflectivePropertyAccessor(); Tester t = new Tester(); t.setProperty("hello"); EvaluationContext ctx = new StandardEvaluationContext(t); assertTrue(rpa.canRead(ctx, t, "property")); assertEquals("hello",rpa.read(ctx, t, "property").getValue()); assertEquals("hello",rpa.read(ctx, t, "property").getValue()); // cached accessor used assertTrue(rpa.canRead(ctx, t, "field")); assertEquals(3,rpa.read(ctx, t, "field").getValue()); assertEquals(3,rpa.read(ctx, t, "field").getValue()); // cached accessor used assertTrue(rpa.canWrite(ctx, t, "property")); rpa.write(ctx, t, "property", "goodbye"); rpa.write(ctx, t, "property", "goodbye"); // cached accessor used assertTrue(rpa.canWrite(ctx, t, "field")); rpa.write(ctx, t, "field", 12); rpa.write(ctx, t, "field", 12); rpa.write(ctx, t, "field2", 3); rpa.write(ctx, t, "property2", "doodoo"); assertEquals(3,rpa.read(ctx, t, "field2").getValue()); assertEquals(0,rpa.read(ctx, t, "field3").getValue()); assertEquals("doodoo",rpa.read(ctx, t, "property3").getValue()); assertEquals(0,rpa .read(ctx, t, "field3").getValue());
@Test public void testOptimalReflectivePropertyAccessor() throws Exception { ReflectivePropertyAccessor rpa = new ReflectivePropertyAccessor(); Tester t = new Tester(); t.setProperty("hello"); EvaluationContext ctx = new StandardEvaluationContext(t); assertTrue(rpa.canRead(ctx, t, "property")); assertEquals("hello", rpa.read(ctx, t, "property").getValue()); assertEquals("hello", rpa.read(ctx, t, "property").getValue()); // cached accessor used PropertyAccessor optA = rpa.createOptimalAccessor(ctx, t, "property"); assertTrue(optA.canRead(ctx, t, "property")); assertFalse(optA.canRead(ctx, t, "property2")); optA = rpa.createOptimalAccessor(ctx, t, "field"); assertTrue(optA.canRead(ctx, t, "field")); assertFalse(optA.canRead(ctx, t, "field2"));
TypeDescriptor typeDescriptor = getTypeDescriptor(context, target, name); if (typeDescriptor != null) { try { Method method = (Method) cachedMember; if (method == null) { method = findSetterForProperty(name, type, target); if (method != null) { cachedMember = method; Field field = (Field) cachedMember; if (field == null) { field = findField(name, type, target); if (field != null) { cachedMember = field;
@Test public void SPR10162_onlyBridgeMethod() throws Exception { ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor(); StandardEvaluationContext context = new StandardEvaluationContext(); Object target = new OnlyBridgeMethod(); TypedValue value = accessor.read(context, target, "property"); assertEquals(Integer.class, value.getTypeDescriptor().getType()); }
if (accessor.canRead(this.evaluationContext, this.targetObject, this.name)) { if (accessor instanceof ReflectivePropertyAccessor) { accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor( this.evaluationContext, this.targetObject, this.name);
@Nullable private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) { Method method = findGetterForProperty(propertyName, clazz, target instanceof Class); if (method == null && target instanceof Class) { method = findGetterForProperty(propertyName, target.getClass(), false); } return method; }
@Nullable private Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) { Method method = findSetterForProperty(propertyName, clazz, target instanceof Class); if (method == null && target instanceof Class) { method = findSetterForProperty(propertyName, target.getClass(), false); } return method; }
/** * Return the method suffixes for a given property name. The default implementation * uses JavaBean conventions with additional support for properties of the form 'xY' * where the method 'getXY()' is used in preference to the JavaBean convention of * 'getxY()'. */ protected String[] getPropertyMethodSuffixes(String propertyName) { String suffix = getPropertyMethodSuffix(propertyName); if (suffix.length() > 0 && Character.isUpperCase(suffix.charAt(0))) { return new String[] {suffix}; } return new String[] {suffix, StringUtils.capitalize(suffix)}; }
@Override public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { return super.canWrite(context, target, name); }
@Override public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { if (target instanceof Message && !PAYLOAD.equals(name) && !HEADERS.equals(name)) { boolean containsKey = ((Message<?>) target).getHeaders().containsKey(name); if (containsKey) { this.typeDescriptor = CodeFlow.toDescriptorFromObject(((Message<?>) target).getHeaders().get(name)); } return containsKey; } return super.canRead(context, target, name); }
TypeDescriptor typeDescriptor = getTypeDescriptor(context, target, name); if (typeDescriptor != null) { try { Method method = (Method) cachedMember; if (method == null) { method = findSetterForProperty(name, type, target); if (method != null) { cachedMember = method; Field field = (Field) cachedMember; if (field == null) { field = findField(name, type, target); if (field != null) { cachedMember = field;
@Test public void SPR9994_bridgeMethods() throws Exception { ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor(); StandardEvaluationContext context = new StandardEvaluationContext(); Object target = new GenericImplementation(); TypedValue value = accessor.read(context, target, "property"); assertEquals(Integer.class, value.getTypeDescriptor().getType()); }
/** * Find a setter method for the specified property. */ @Nullable protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) { return findMethodForProperty(getPropertyMethodSuffixes(propertyName), "set", clazz, mustBeStatic, 1, ANY_TYPES); }
/** * Find a field of a certain name on a specified class. */ @Nullable protected Field findField(String name, Class<?> clazz, boolean mustBeStatic) { Field[] fields = clazz.getFields(); for (Field field : fields) { if (field.getName().equals(name) && (!mustBeStatic || Modifier.isStatic(field.getModifiers()))) { return field; } } // We'll search superclasses and implemented interfaces explicitly, // although it shouldn't be necessary - however, see SPR-10125. if (clazz.getSuperclass() != null) { Field field = findField(name, clazz.getSuperclass(), mustBeStatic); if (field != null) { return field; } } for (Class<?> implementedInterface : clazz.getInterfaces()) { Field field = findField(name, implementedInterface, mustBeStatic); if (field != null) { return field; } } return null; }