From c3a639f07db882eac7613c1ebae96bc076fed1a9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 29 Jul 2010 13:49:09 +0000 Subject: [PATCH] fixed concurrency issue in TypedStringValue, showing for nested typed Maps in prototype beans (SPR-7398); optimized building of keyed arg names in BeanDefinitionValueResolver --- .../factory/config/TypedStringValue.java | 16 ++++---- .../support/BeanDefinitionValueResolver.java | 38 +++++++++++++------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java index de3dbc25c3a..01e7cb52e2f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/TypedStringValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ public class TypedStringValue implements BeanMetadataElement { private String value; - private Object targetType; + private volatile Object targetType; private Object source; @@ -110,10 +110,11 @@ public class TypedStringValue implements BeanMetadataElement { * Return the type to convert to. */ public Class getTargetType() { - if (!(this.targetType instanceof Class)) { + Object targetTypeValue = this.targetType; + if (!(targetTypeValue instanceof Class)) { throw new IllegalStateException("Typed String value does not carry a resolved target type"); } - return (Class) this.targetType; + return (Class) targetTypeValue; } /** @@ -128,11 +129,12 @@ public class TypedStringValue implements BeanMetadataElement { * Return the type to convert to. */ public String getTargetTypeName() { - if (this.targetType instanceof Class) { - return ((Class) this.targetType).getName(); + Object targetTypeValue = this.targetType; + if (targetTypeValue instanceof Class) { + return ((Class) targetTypeValue).getName(); } else { - return (String) this.targetType; + return (String) targetTypeValue; } } diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java index 28de671c6ce..8220ee353bd 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -338,9 +338,7 @@ class BeanDefinitionValueResolver { Object resolved = Array.newInstance(elementType, ml.size()); for (int i = 0; i < ml.size(); i++) { Array.set(resolved, i, - resolveValueIfNecessary( - argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX, - ml.get(i))); + resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); } return resolved; } @@ -352,9 +350,7 @@ class BeanDefinitionValueResolver { List resolved = new ArrayList(ml.size()); for (int i = 0; i < ml.size(); i++) { resolved.add( - resolveValueIfNecessary( - argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX, - ml.get(i))); + resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); } return resolved; } @@ -366,8 +362,7 @@ class BeanDefinitionValueResolver { Set resolved = new LinkedHashSet(ms.size()); int i = 0; for (Object m : ms) { - resolved.add(resolveValueIfNecessary( - argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + i + BeanWrapper.PROPERTY_KEY_SUFFIX, m)); + resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m)); i++; } return resolved; @@ -381,11 +376,32 @@ class BeanDefinitionValueResolver { for (Map.Entry entry : mm.entrySet()) { Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey()); Object resolvedValue = resolveValueIfNecessary( - argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + entry.getKey() + - BeanWrapper.PROPERTY_KEY_SUFFIX, entry.getValue()); + new KeyedArgName(argName, entry.getKey()), entry.getValue()); resolved.put(resolvedKey, resolvedValue); } return resolved; } + + /** + * Holder class used for delayed toString building. + */ + private static class KeyedArgName { + + private final Object argName; + + private final Object key; + + public KeyedArgName(Object argName, Object key) { + this.argName = argName; + this.key = key; + } + + @Override + public String toString() { + return this.argName + " with key " + BeanWrapper.PROPERTY_KEY_PREFIX + + this.key + BeanWrapper.PROPERTY_KEY_SUFFIX; + } + } + }