Skip to content

Commit 643296e

Browse files
Change the way the bean properties map works to allow it to be cleared
1 parent df3d084 commit 643296e

File tree

3 files changed

+212
-173
lines changed

3 files changed

+212
-173
lines changed

src/main/java/javax/el/BeanELResolver.java

+9-173
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,20 @@
5858

5959
package javax.el;
6060

61+
62+
import org.jboss.el.cache.BeanPropertiesCache;
63+
6164
import java.lang.reflect.InvocationTargetException;
6265
import java.lang.reflect.Method;
63-
import java.lang.reflect.Modifier;
64-
import java.lang.ref.SoftReference;
65-
import java.lang.ref.ReferenceQueue;
6666
import java.beans.FeatureDescriptor;
6767
import java.beans.BeanInfo;
6868
import java.beans.Introspector;
6969
import java.beans.PropertyDescriptor;
70-
import java.beans.IntrospectionException;
7170
import java.util.Iterator;
7271
import java.util.ArrayList;
73-
import java.util.Map;
74-
import java.util.HashMap;
75-
import java.util.concurrent.ConcurrentHashMap;
72+
73+
import static org.jboss.el.cache.BeanPropertiesCache.BeanProperties;
74+
import static org.jboss.el.cache.BeanPropertiesCache.BeanProperty;
7675

7776
/**
7877
* Defines property resolution behavior on objects using the JavaBeans
@@ -113,129 +112,8 @@
113112
*/
114113
public class BeanELResolver extends ELResolver {
115114

116-
static private class BPSoftReference extends SoftReference<BeanProperties> {
117-
final Class<?> key;
118-
BPSoftReference(Class<?> key, BeanProperties beanProperties,
119-
ReferenceQueue<BeanProperties> refQ) {
120-
super(beanProperties, refQ);
121-
this.key = key;
122-
}
123-
}
124-
125-
static private class SoftConcurrentHashMap extends
126-
ConcurrentHashMap<Class<?>, BeanProperties> {
127-
128-
private static final int CACHE_INIT_SIZE = 1024;
129-
private ConcurrentHashMap<Class<?>, BPSoftReference> map =
130-
new ConcurrentHashMap<Class<?>, BPSoftReference>(CACHE_INIT_SIZE);
131-
private ReferenceQueue<BeanProperties> refQ =
132-
new ReferenceQueue<BeanProperties>();
133-
134-
// Remove map entries that have been placed on the queue by GC.
135-
private void cleanup() {
136-
BPSoftReference BPRef = null;
137-
while ((BPRef = (BPSoftReference)refQ.poll()) != null) {
138-
map.remove(BPRef.key);
139-
}
140-
}
141-
142-
@Override
143-
public BeanProperties put(Class<?> key, BeanProperties value) {
144-
cleanup();
145-
BPSoftReference prev =
146-
map.put(key, new BPSoftReference(key, value, refQ));
147-
return prev == null? null: prev.get();
148-
}
149-
150-
@Override
151-
public BeanProperties putIfAbsent(Class<?> key, BeanProperties value) {
152-
cleanup();
153-
BPSoftReference prev =
154-
map.putIfAbsent(key, new BPSoftReference(key, value, refQ));
155-
return prev == null? null: prev.get();
156-
}
157-
158-
@Override
159-
public BeanProperties get(Object key) {
160-
cleanup();
161-
BPSoftReference BPRef = map.get(key);
162-
if (BPRef == null) {
163-
return null;
164-
}
165-
if (BPRef.get() == null) {
166-
// value has been garbage collected, remove entry in map
167-
map.remove(key);
168-
return null;
169-
}
170-
return BPRef.get();
171-
}
172-
}
173-
174115
private boolean isReadOnly;
175116

176-
private static final SoftConcurrentHashMap properties =
177-
new SoftConcurrentHashMap();
178-
179-
/*
180-
* Defines a property for a bean.
181-
*/
182-
final static class BeanProperty {
183-
184-
private Method readMethod;
185-
private Method writeMethod;
186-
private PropertyDescriptor descriptor;
187-
188-
public BeanProperty(Class<?> baseClass,
189-
PropertyDescriptor descriptor) {
190-
this.descriptor = descriptor;
191-
readMethod = getMethod(baseClass, descriptor.getReadMethod());
192-
writeMethod = getMethod(baseClass, descriptor.getWriteMethod());
193-
}
194-
195-
public Class getPropertyType() {
196-
return descriptor.getPropertyType();
197-
}
198-
199-
public boolean isReadOnly() {
200-
return getWriteMethod() == null;
201-
}
202-
203-
public Method getReadMethod() {
204-
return readMethod;
205-
}
206-
207-
public Method getWriteMethod() {
208-
return writeMethod;
209-
}
210-
}
211-
212-
/*
213-
* Defines the properties for a bean.
214-
*/
215-
final static class BeanProperties {
216-
217-
private final Map<String, BeanProperty> propertyMap =
218-
new HashMap<String, BeanProperty>();
219-
220-
public BeanProperties(Class<?> baseClass) {
221-
PropertyDescriptor[] descriptors;
222-
try {
223-
BeanInfo info = Introspector.getBeanInfo(baseClass);
224-
descriptors = info.getPropertyDescriptors();
225-
} catch (IntrospectionException ie) {
226-
throw new ELException(ie);
227-
}
228-
for (PropertyDescriptor pd: descriptors) {
229-
propertyMap.put(pd.getName(),
230-
new BeanProperty(baseClass, pd));
231-
}
232-
}
233-
234-
public BeanProperty getBeanProperty(String property) {
235-
return propertyMap.get(property);
236-
}
237-
}
238-
239117
/**
240118
* Creates a new read/write <code>BeanELResolver</code>.
241119
*/
@@ -526,7 +404,7 @@ public Object invoke(ELContext context,
526404
}
527405
Method m = ELUtil.findMethod(base.getClass(), method.toString(),
528406
paramTypes,params, false);
529-
m = getMethod(base.getClass(), m);
407+
m = BeanPropertiesCache.getMethod(base.getClass(), m);
530408
for (Object p: params) {
531409
// If the parameters is a LambdaExpression, set the ELContext
532410
// for its evaluation
@@ -672,59 +550,17 @@ public Class<?> getCommonPropertyType(ELContext context,
672550
return Object.class;
673551
}
674552

675-
/*
676-
* Get a public method form a public class or interface of a given method.
677-
* Note that if a PropertyDescriptor is obtained for a non-public class that
678-
* implements a public interface, the read/write methods will be for the
679-
* class, and therefore inaccessible. To correct this, a version of the
680-
* same method must be found in a superclass or interface.
681-
**/
682-
683-
static private Method getMethod(Class<?> cl, Method method) {
684-
685-
if (method == null) {
686-
return null;
687-
}
688-
689-
if (Modifier.isPublic (cl.getModifiers ())) {
690-
return method;
691-
}
692-
Class<?> [] interfaces = cl.getInterfaces ();
693-
for (int i = 0; i < interfaces.length; i++) {
694-
Class<?> c = interfaces[i];
695-
Method m = null;
696-
try {
697-
m = c.getMethod(method.getName(), method.getParameterTypes());
698-
c = m.getDeclaringClass();
699-
if ((m = getMethod(c, m)) != null)
700-
return m;
701-
} catch (NoSuchMethodException ex) {
702-
}
703-
}
704-
Class<?> c = cl.getSuperclass();
705-
if (c != null) {
706-
Method m = null;
707-
try {
708-
m = c.getMethod(method.getName(), method.getParameterTypes());
709-
c = m.getDeclaringClass();
710-
if ((m = getMethod(c, m)) != null)
711-
return m;
712-
} catch (NoSuchMethodException ex) {
713-
}
714-
}
715-
return null;
716-
}
717553

718554
private BeanProperty getBeanProperty(ELContext context,
719555
Object base,
720556
Object prop) {
721557

722558
String property = prop.toString();
723559
Class baseClass = base.getClass();
724-
BeanProperties bps = properties.get(baseClass);
560+
BeanProperties bps = BeanPropertiesCache.getProperties().get(baseClass);
725561
if (bps == null) {
726562
bps = new BeanProperties(baseClass);
727-
properties.put(baseClass, bps);
563+
BeanPropertiesCache.getProperties().put(baseClass, bps);
728564
}
729565
BeanProperty bp = bps.getBeanProperty(property);
730566
if (bp == null) {

0 commit comments

Comments
 (0)