View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.validatebeanbehavior;
20  
21  import javax.el.ELContext;
22  import javax.el.ELResolver;
23  import javax.el.ValueExpression;
24  import java.beans.FeatureDescriptor;
25  import java.util.Iterator;
26  
27  /**
28   * This class inspects the EL expression and returns a ValueReferenceWrapper
29   * when Unified EL is not available.
30   *
31   * Note: Copy from MyFaces Core 2.0.
32   */
33  final class ValueReferenceResolver extends ELResolver {
34      private final ELResolver resolver;
35  
36      /**
37       * This is a simple solution to keep track of the resolved objects,
38       * since ELResolver provides no way to know if the current ELResolver
39       * is the last one in the chain. By assigning (and effectively overwriting)
40       * this field, we know that the value after invoking the chain is always
41       * the last one.
42       * <p/>
43       * This solution also deals with nested objects (like: #{myBean.prop.prop.prop}.
44       */
45      private ValueReferenceWrapper lastObject;
46  
47      /**
48       * Constructor is only used internally.
49       *
50       * @param elResolver An ELResolver from the current ELContext.
51       */
52      ValueReferenceResolver(final ELResolver elResolver) {
53          this.resolver = elResolver;
54      }
55  
56      /**
57       * This method can be used to extract the ValueReferenceWrapper from the given ValueExpression.
58       *
59       * @param valueExpression The ValueExpression to resolve.
60       * @param elCtx           The ELContext, needed to parse and execute the expression.
61       * @return The ValueReferenceWrapper.
62       */
63      public static ValueReferenceWrapper resolve(final ValueExpression valueExpression, final ELContext elCtx) {
64          final ValueReferenceResolver resolver = new ValueReferenceResolver(elCtx.getELResolver());
65          valueExpression.getValue(new ELContextDecorator(elCtx, resolver));
66          return resolver.lastObject;
67      }
68  
69      /**
70       * This method is the only one that matters. It keeps track of the objects in the EL expression.
71       * <p/>
72       * It creates a new ValueReferenceWrapper and assigns it to lastObject.
73       *
74       * @param context  The ELContext.
75       * @param base     The base object, may be null.
76       * @param property The property, may be null.
77       * @return The resolved value
78       */
79      @Override
80      public Object getValue(final ELContext context, final Object base, final Object property) {
81          lastObject = new ValueReferenceWrapper(base, property);
82          return resolver.getValue(context, base, property);
83      }
84  
85      // ############################ Standard delegating implementations ############################
86  
87      public final Class<?> getType(final ELContext ctx, final Object base, final Object property) {
88          return resolver.getType(ctx, base, property);
89      }
90  
91      public final void setValue(final ELContext ctx, final Object base, final Object property, final Object value) {
92          resolver.setValue(ctx, base, property, value);
93      }
94  
95      public final boolean isReadOnly(final ELContext ctx, final Object base, final Object property) {
96          return resolver.isReadOnly(ctx, base, property);
97      }
98  
99      public final Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext ctx, final Object base) {
100         return resolver.getFeatureDescriptors(ctx, base);
101     }
102 
103     public final Class<?> getCommonPropertyType(final ELContext ctx, final Object base) {
104         return resolver.getCommonPropertyType(ctx, base);
105     }
106 
107 }