You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2016/08/05 16:46:35 UTC
incubator-juneau git commit:
https://issues.apache.org/jira/browse/JUNEAU-4?
Repository: incubator-juneau
Updated Branches:
refs/heads/master dabe77a54 -> 4bc7b351c
https://issues.apache.org/jira/browse/JUNEAU-4?
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/4bc7b351
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/4bc7b351
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/4bc7b351
Branch: refs/heads/master
Commit: 4bc7b351c27cc14c0b1e0ce281a985a9fbe2c525
Parents: dabe77a
Author: jamesbognar <ja...@gmail.com>
Authored: Fri Aug 5 12:46:30 2016 -0400
Committer: jamesbognar <ja...@gmail.com>
Committed: Fri Aug 5 12:46:30 2016 -0400
----------------------------------------------------------------------
.../java/org/apache/juneau/ContextFactory.java | 125 ++++++++++---------
.../org/apache/juneau/internal/HashCode.java | 18 ++-
.../org/apache/juneau/CT_ContextFactory.java | 1 -
.../src/test/java/org/apache/juneau/a/A1.java | 4 +
4 files changed, 84 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/4bc7b351/org.apache.juneau/src/main/java/org/apache/juneau/ContextFactory.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau/src/main/java/org/apache/juneau/ContextFactory.java b/org.apache.juneau/src/main/java/org/apache/juneau/ContextFactory.java
index becf8f1..bc957ca 100644
--- a/org.apache.juneau/src/main/java/org/apache/juneau/ContextFactory.java
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/ContextFactory.java
@@ -239,7 +239,7 @@ public final class ContextFactory extends Lockable {
// All configuration properties in this object.
// Keys are property prefixes (e.g. 'BeanContext').
// Values are maps containing properties for that specific prefix.
- private Map<String,PropertyMap> properties = new ConcurrentHashMap<String,PropertyMap>();
+ private Map<String,PropertyMap> properties = new ConcurrentSkipListMap<String,PropertyMap>();
// Context cache.
// This gets cleared every time any properties change on this object.
@@ -248,7 +248,7 @@ public final class ContextFactory extends Lockable {
// Global Context cache.
// Context factories that are the 'same' will use the same maps from this cache.
// 'same' means the context properties are all the same when converted to strings.
- private static final ConcurrentHashMap<ContextFactory, ConcurrentHashMap<Class<? extends Context>,Context>> globalContextCache = new ConcurrentHashMap<ContextFactory, ConcurrentHashMap<Class<? extends Context>,Context>>();
+ private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Class<? extends Context>,Context>> globalContextCache = new ConcurrentHashMap<Integer, ConcurrentHashMap<Class<? extends Context>,Context>>();
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock rl = lock.readLock(), wl = lock.writeLock();
@@ -264,7 +264,7 @@ public final class ContextFactory extends Lockable {
private static Comparator<Object> PROPERTY_COMPARATOR = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
- return ContextFactory.toString(o1).compareTo(ContextFactory.toString(o2));
+ return normalize(o1).toString().compareTo(normalize(o2).toString());
}
};
@@ -546,9 +546,10 @@ public final class ContextFactory extends Lockable {
if (! contexts.containsKey(c)) {
// Try to get it from the global cache.
- if (! globalContextCache.containsKey(this))
- globalContextCache.putIfAbsent(clone(), new ConcurrentHashMap<Class<? extends Context>,Context>());
- ConcurrentHashMap<Class<? extends Context>, Context> cacheForThisConfig = globalContextCache.get(this);
+ Integer key = hashCode();
+ if (! globalContextCache.containsKey(key))
+ globalContextCache.putIfAbsent(key, new ConcurrentHashMap<Class<? extends Context>,Context>());
+ ConcurrentHashMap<Class<? extends Context>, Context> cacheForThisConfig = globalContextCache.get(key);
if (! cacheForThisConfig.containsKey(c))
cacheForThisConfig.putIfAbsent(c, c.getConstructor(ContextFactory.class).newInstance(this));
@@ -733,16 +734,10 @@ public final class ContextFactory extends Lockable {
@Override /* Object */
public int hashCode() {
- return this.properties.hashCode();
- }
-
- @Override /* Object */
- public boolean equals(Object o) {
- if (o instanceof ContextFactory) {
- ContextFactory c = (ContextFactory)o;
- return c.properties.equals(properties);
- }
- return false;
+ HashCode c = new HashCode();
+ for (PropertyMap m : properties.values())
+ c.add(m);
+ return c.get();
}
//--------------------------------------------------------------------------------
@@ -750,6 +745,17 @@ public final class ContextFactory extends Lockable {
//--------------------------------------------------------------------------------
/**
+ * Hashcode generator that treats strings and primitive values the same.
+ * (e.g. <code>123</code> and <js>"123"</js> result in the same hashcode.)
+ */
+ protected static class NormalizingHashCode extends HashCode {
+ @Override /* HashCode */
+ protected Object normalize(Object o) {
+ return ContextFactory.normalize(o);
+ }
+ }
+
+ /**
* Contains all the properties for a particular property prefix (e.g. <js>'BeanContext'</js>)
* <p>
* Instances of this map are immutable from outside this class.
@@ -762,12 +768,14 @@ public final class ContextFactory extends Lockable {
@SuppressWarnings("hiding")
public class PropertyMap {
- private Map<String,Property> map = new ConcurrentSkipListMap<String,Property>();
- volatile int hashCode = 0;
- ReadWriteLock lock = new ReentrantReadWriteLock();
- Lock rl = lock.readLock(), wl = lock.writeLock();
+ private final Map<String,Property> map = new ConcurrentSkipListMap<String,Property>();
+ private volatile int hashCode = 0;
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock rl = lock.readLock(), wl = lock.writeLock();
+ private final String prefix;
private PropertyMap(String prefix) {
+ this.prefix = prefix;
prefix = prefix + '.';
Properties p = System.getProperties();
for (Map.Entry<Object,Object> e : p.entrySet())
@@ -779,6 +787,7 @@ public final class ContextFactory extends Lockable {
* Copy constructor.
*/
private PropertyMap(PropertyMap orig) {
+ this.prefix = orig.prefix;
for (Map.Entry<String,Property> e : orig.map.entrySet())
this.map.put(e.getKey(), Property.create(e.getValue().name, e.getValue().value()));
}
@@ -926,7 +935,7 @@ public final class ContextFactory extends Lockable {
rl.lock();
try {
if (hashCode == 0) {
- HashCode c = HashCode.create();
+ HashCode c = new HashCode().add(prefix);
for (Property p : map.values())
c.add(p);
this.hashCode = c.get();
@@ -955,15 +964,11 @@ public final class ContextFactory extends Lockable {
@Override
public String toString() {
- ObjectMap m = new ObjectMap();
- m.put("id", System.identityHashCode(this));
- m.put("hashcode", hashCode());
- m.put("values", map);
- return JsonSerializer.DEFAULT_LAX.toString(m);
+ return "PropertyMap(id="+System.identityHashCode(this)+")";
}
}
- private abstract static class Property implements Comparable<Property> {
+ private abstract static class Property {
private final String name, type;
private final Object value;
@@ -1005,36 +1010,22 @@ public final class ContextFactory extends Lockable {
@Override /* Object */
public int hashCode() {
- HashCode c = HashCode.create().add(name);
+ HashCode c = new NormalizingHashCode().add(name);
if (value instanceof Map) {
for (Map.Entry<?,?> e : ((Map<?,?>)value).entrySet())
- c.add(ContextFactory.toString(e.getKey())).add(ContextFactory.toString(e.getValue()));
+ c.add(e.getKey()).add(e.getValue());
} else if (value instanceof Collection) {
for (Object o : (Collection<?>)value)
- c.add(ContextFactory.toString(o));
+ c.add(o);
} else {
- c.add(ContextFactory.toString(value));
+ c.add(value);
}
return c.get();
}
- @Override /* Object */
- public boolean equals(Object o) {
- if (o instanceof Property) {
- Property p = (Property)o;
- return ContextFactory.same(value, p.value);
- }
- return false;
- }
-
- @Override
- public int compareTo(Property p) {
- return name.compareTo(p.name);
- }
-
@Override
public String toString() {
- return JsonSerializer.DEFAULT_LAX.toString(value);
+ return "Property(name="+name+",type="+type+")";
}
}
@@ -1064,12 +1055,14 @@ public final class ContextFactory extends Lockable {
for (Object o : (Collection<Object>)val)
add(o);
else {
- String s = val.toString();
- if (s.startsWith("[") && s.endsWith("]")) {
- try {
- add(new ObjectList(s));
- return;
- } catch (Exception e) {}
+ if (val instanceof String) {
+ String s = val.toString();
+ if (s.startsWith("[") && s.endsWith("]")) {
+ try {
+ add(new ObjectList(s));
+ return;
+ } catch (Exception e) {}
+ }
}
for (Object o : value)
if (same(val, o))
@@ -1087,12 +1080,14 @@ public final class ContextFactory extends Lockable {
for (Object o : (Collection<Object>)val)
remove(o);
else {
- String s = val.toString();
- if (s.startsWith("[") && s.endsWith("]")) {
- try {
- remove(new ObjectList(s));
- return;
- } catch (Exception e) {}
+ if (val instanceof String) {
+ String s = val.toString();
+ if (s.startsWith("[") && s.endsWith("]")) {
+ try {
+ remove(new ObjectList(s));
+ return;
+ } catch (Exception e) {}
+ }
}
for (Iterator<Object> i = value.iterator(); i.hasNext();)
if (same(i.next(), val))
@@ -1201,10 +1196,18 @@ public final class ContextFactory extends Lockable {
}
}
- private static String toString(Object o) {
+ /**
+ * Converts an object to a normalized form for comparison purposes.
+ *
+ * @param o The object to normalize.
+ * @return The normalized object.
+ */
+ private static final Object normalize(Object o) {
if (o instanceof Class)
return ((Class<?>)o).getName();
- return o.toString();
+ if (o instanceof Number || o instanceof Boolean)
+ return o.toString();
+ return o;
}
/*
@@ -1244,7 +1247,7 @@ public final class ContextFactory extends Lockable {
}
return false;
} else {
- return ContextFactory.toString(o1).equals(ContextFactory.toString(o2));
+ return normalize(o1).equals(normalize(o2));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/4bc7b351/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java b/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
index 5bdfb80..fc1e72b 100644
--- a/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
@@ -22,7 +22,7 @@ package org.apache.juneau.internal;
*
* @author James Bognar (james.bognar@salesforce.com)
*/
-public final class HashCode {
+public class HashCode {
private int hashCode = 1;
@@ -35,7 +35,6 @@ public final class HashCode {
return new HashCode();
}
-
/**
* Hashes the hashcode of the specified object into this object.
*
@@ -43,6 +42,7 @@ public final class HashCode {
* @return This object (for method chaining).
*/
public HashCode add(Object o) {
+ o = normalize(o);
add(o == null ? 1 : o.hashCode());
return this;
}
@@ -68,4 +68,18 @@ public final class HashCode {
public int get() {
return hashCode;
}
+
+ /**
+ * Converts the object to a normalized form before grabbing it's hashcode.
+ * Subclasses can override this method to provide specialized handling
+ * (e.g. converting numbers to strings so that <code>123</code> and <js>"123"</js>
+ * end up creating the same hashcode.)
+ * Default implementation does nothing.
+ *
+ * @param o The object to normalize before getting it's hashcode.
+ * @return The normalized object.
+ */
+ protected Object normalize(Object o) {
+ return o;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/4bc7b351/org.apache.juneau/src/test/java/org/apache/juneau/CT_ContextFactory.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau/src/test/java/org/apache/juneau/CT_ContextFactory.java b/org.apache.juneau/src/test/java/org/apache/juneau/CT_ContextFactory.java
index 865552c..271410c 100644
--- a/org.apache.juneau/src/test/java/org/apache/juneau/CT_ContextFactory.java
+++ b/org.apache.juneau/src/test/java/org/apache/juneau/CT_ContextFactory.java
@@ -202,7 +202,6 @@ public class CT_ContextFactory {
ContextFactory.PropertyMap p1 = f1.getPropertyMap("A");
ContextFactory.PropertyMap p2 = f2.getPropertyMap("A");
assertEquals(p1.hashCode(), p2.hashCode());
- assertTrue(p1.equals(p2));
}
@SuppressWarnings("unchecked")
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/4bc7b351/org.apache.juneau/src/test/java/org/apache/juneau/a/A1.java
----------------------------------------------------------------------
diff --git a/org.apache.juneau/src/test/java/org/apache/juneau/a/A1.java b/org.apache.juneau/src/test/java/org/apache/juneau/a/A1.java
index e93afa0..6b663c8 100755
--- a/org.apache.juneau/src/test/java/org/apache/juneau/a/A1.java
+++ b/org.apache.juneau/src/test/java/org/apache/juneau/a/A1.java
@@ -88,6 +88,7 @@ public class A1 {
return x;
}
+ @Bean(sort=true)
public static class A2 {
public int f1;
protected int f2;
@@ -112,6 +113,7 @@ public class A1 {
}
}
+ @Bean(sort=true)
protected static class A3 {
public int f1;
protected int f2;
@@ -136,6 +138,7 @@ public class A1 {
}
}
+ @Bean(sort=true)
static class A4 {
public int f1;
protected int f2;
@@ -160,6 +163,7 @@ public class A1 {
}
}
+ @Bean(sort=true)
private static class A5 {
public int f1;
protected int f2;