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;