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 <[email protected]>
Authored: Fri Aug 5 12:46:30 2016 -0400
Committer: jamesbognar <[email protected]>
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 ([email protected])
  */
-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;

Reply via email to