I know that BeanWrapper will bind Map properties where the key is a String. I also know that I can get BeanWrapper to convert between a String and an Object by registering a custom editor. I have done both things successfully, but I can't get the combination to work: having BeanWrapper work with a Map property that uses a custom editor to translate a String into an Object and use that as the key. Does anyone know if this is a limitation of BeanWrapper, or if I'm just going about it wrong?
Here's my test case... I have a Product with an arbitrary number of Prices. Product contains a Map<PriceType,Price> prices attribute. A Product may have one Price of each PriceType, but is not required to. Some irrelevant code is obviously omitted from the following:
The result is that the key in the map ends up being the string value of the type's ID, and not the ID itself. Yet I know when I use the custom binder as a straight object (not part of a map) it translate correctly between a String id and an object.Code:public void testMapObjectKey() throws Exception { BeanWrapper wrapper = new BeanWrapperImpl(); Price oldPrice = new Price(10D); Price newPrice = new Price(20D); PriceType type = getTestPriceType(true); Product product = getTestProduct(true); wrapper.setWrappedInstance(product); Map<PriceType, Price> prices = product.getPrices(); prices.put(type, oldPrice); assertTrue(product.getPrices().get(type).equals(oldPrice)); wrapper.registerCustomEditor(prices.getClass(), new PriceTypeBinder()); assertEquals(wrapper.findCustomEditor(prices.getClass(), "prices").getClass(), PriceTypeBinder.class); String idStr = type.getId().toString(); wrapper.setPropertyValue("prices['" + idStr + "']", newPrice); Object key = null; for (Object ob : prices.keySet()) { if ((prices.get(ob)).equals(newPrice)) key = ob; } assertEquals("Key for new value is wrong", type, key); assertEquals(newPrice, product.getPrices().get(type)); }
As I debug into BeanWrapper, it seems like this is a limitation of BeanWrapper's implementation and not an error in my approach. (Am I wrong?)
BeanWrapper's setPropertyValue() checks the registered custom editors and converts Strings to alternate types if needed via a call to doTypeConversionIfNecessary(). It seems as if, to do what I want to do, that getPropertyValue() should also make this check.
Specifically, around line 695 in version 1.2.3, instead of:
It might do something like this:Code:else if (value instanceof Map) { Map map = (Map) value; value = map.get(key); }
Is there a reason not to do this? Is it something that would generally be useful to others without breaking anything, and hence I should submit a patch, or would I be better of creating a custom BeanWrapper just for my needs?Code:else if (value instanceof Map) { Map map = (Map) value; Object convertedKey = doTypeConversionIfNecessary(...) value = map.get(convertedKey); }


Reply With Quote