Announcement Announcement Module
Collapse
No announcement yet.
Can BeanWrapper resolve Maps with non-string keys? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Can BeanWrapper resolve Maps with non-string keys?

    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:

    Code:
    	public void testMapObjectKey&#40;&#41; throws Exception &#123;
    		BeanWrapper wrapper = new BeanWrapperImpl&#40;&#41;;
    		Price oldPrice = new Price&#40;10D&#41;;
    		Price newPrice = new Price&#40;20D&#41;;
    		PriceType type = getTestPriceType&#40;true&#41;;
    		Product product = getTestProduct&#40;true&#41;;
    		wrapper.setWrappedInstance&#40;product&#41;;
    
    		Map<PriceType, Price> prices = product.getPrices&#40;&#41;;
    		prices.put&#40;type, oldPrice&#41;;
    		assertTrue&#40;product.getPrices&#40;&#41;.get&#40;type&#41;.equals&#40;oldPrice&#41;&#41;;
    
    		wrapper.registerCustomEditor&#40;prices.getClass&#40;&#41;, new PriceTypeBinder&#40;&#41;&#41;;
    		assertEquals&#40;wrapper.findCustomEditor&#40;prices.getClass&#40;&#41;, "prices"&#41;.getClass&#40;&#41;, PriceTypeBinder.class&#41;;
    		String idStr = type.getId&#40;&#41;.toString&#40;&#41;;
    		wrapper.setPropertyValue&#40;"prices&#91;'" + idStr + "'&#93;", newPrice&#41;;
    		Object key = null;
    		for &#40;Object ob &#58; prices.keySet&#40;&#41;&#41; &#123;
    			if &#40;&#40;prices.get&#40;ob&#41;&#41;.equals&#40;newPrice&#41;&#41; key = ob;
    		&#125;
    
    		assertEquals&#40;"Key for new value is wrong", type, key&#41;;
    		assertEquals&#40;newPrice, product.getPrices&#40;&#41;.get&#40;type&#41;&#41;;
    	&#125;
    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.

    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:

    Code:
        else if &#40;value instanceof Map&#41; &#123;
            Map map = &#40;Map&#41; value;
            value = map.get&#40;key&#41;;
        &#125;
    It might do something like this:

    Code:
        else if &#40;value instanceof Map&#41; &#123;
            Map map = &#40;Map&#41; value;
            Object convertedKey = doTypeConversionIfNecessary&#40;...&#41;
            value = map.get&#40;convertedKey&#41;;
        &#125;
    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?

  • #2
    Code:
    else if &#40;value instanceof Map&#41; &#123;
            Map map = &#40;Map&#41; value;
            Object convertedKey = doTypeConversionIfNecessary&#40;...&#41;
            value = map.get&#40;convertedKey&#41;;
        &#125;
    That "..." in your sample code leaves out a awful lot of detail ;-) It's not trivial at all to determine the correct type to convert to - in fact it's impossible in Java 1.3/4 and I'm fairly sure because of type erasure it's also impossible in Java 1.5 (I've not really played with the new generics reflection features in 1.5 so I can't be sure).

    Ollie

    Comment

    Working...
    X