Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-196

Lack of useAttributeFor in XStreamMarshaller

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.0
    • Fix Version/s: 1.0.2
    • Component/s: OXM
    • Labels:
      None

      Description

      There is no possibility to set useAttributeFor in XStreamMarshaller class. I think this should be added. Followin code added to XStreamMarshaller should solve this problem

      public void setUseAttributeFor(Map aliases) {
      if (logger.isDebugEnabled())

      { logger.debug("setUseAttributeFor(Map) - start"); //$NON-NLS-1$ }

      for (Iterator iterator = aliases.entrySet().iterator(); iterator.hasNext() {
      Map.Entry entry = (Map.Entry) iterator.next();
      // Check whether we need to convert from String to Class.
      Class type = null;
      if (entry.getKey() instanceof Class)

      { type = (Class) entry.getKey(); }

      else

      { ClassEditor editor = new ClassEditor(); editor.setAsText(String.valueOf(entry.getKey())); type = (Class) editor.getValue(); }

      addAttribute((String) entry.getValue(), type);
      }

      if (logger.isDebugEnabled())

      { logger.debug("setUseAttributeFor(Map) - end"); //$NON-NLS-1$ }

      }

      public void addAttribute(String name, Class type) {
      if (logger.isDebugEnabled())

      { logger.debug("addAttribute(String, Class) - start"); //$NON-NLS-1$ logger.debug("addAttribute(String, Class) - name=" + name + ", type=" + type); //$NON-NLS-1$ //$NON-NLS-2$ }

      xstream.useAttributeFor(type, name);

      if (logger.isDebugEnabled())

      { logger.debug("addAttribute(String, Class) - end"); //$NON-NLS-1$ }

      }

      then using attributes can be defined as:

      <property name="useAttributeFor">
      <props>
      <prop key="pl.test.example">version</prop>
      <prop key="pl.test.sample">version</prop>
      </props>
      </property>

        Activity

        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        There is one problem here: the useAttributeFor method is overloaded, offering three variants:

        void useAttributeFor(Class type)
        Use an XML attribute for an arbitrary type.
        void useAttributeFor(Class definedIn, String fieldName)
        Use an XML attribute for a field declared in a specific type.
        void useAttributeFor(String fieldName, Class type)
        Use an XML attribute for a field or a specific type.

        It seems unfitting to just expose one of those options, because all three have a specific purpose. It seems better to offer all three, through two separate properties, because the JavaBeans spec doesn't allow overloaded properties:

        setUseAttributeForTypes(Class[] types)
        and
        setUseAttributeFor(Map attributes), where the Map can either be a Map<Class, String>, or a Map<String, Class>.

        Show
        arjen.poutsma Arjen Poutsma added a comment - There is one problem here: the useAttributeFor method is overloaded, offering three variants: void useAttributeFor(Class type) Use an XML attribute for an arbitrary type. void useAttributeFor(Class definedIn, String fieldName) Use an XML attribute for a field declared in a specific type. void useAttributeFor(String fieldName, Class type) Use an XML attribute for a field or a specific type. It seems unfitting to just expose one of those options, because all three have a specific purpose. It seems better to offer all three, through two separate properties, because the JavaBeans spec doesn't allow overloaded properties: setUseAttributeForTypes(Class[] types) and setUseAttributeFor(Map attributes), where the Map can either be a Map<Class, String>, or a Map<String, Class>.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Closing 1.0.2 issues.

        Show
        arjen.poutsma Arjen Poutsma added a comment - Closing 1.0.2 issues.
        Hide
        ranma172 Frank Martin added a comment -

        Hello,

        I was creating my own XStreamMarshaller but I discovered there is already one in Spring.

        However, I've seen a problem with the method setUseAttributeFor(Map attributes).

        Map interface says "A map cannot contain duplicate keys". That means you can't set two attribute names for the same class or two classes for the same attribute name.

        For example, with XStream you can set two attributes for some class:

        xstream.useAttributeFor(Person.class, "name");
        xstream.useAttributeFor(Person.class, "address");

        But you can't do it with setUseAttributeFor(Map) because:

        Map map = new HashMap();
        map.put(Person.class, "name");
        map.put(Person.class, "address"); // Overwrites the previous value of Person.class key !!!
        marshaller.setUseAttributeFor(map); // Only sets attribute "address" !!!

        Here's one example solution. Map values could be a List of Strings (containing all the attributes) rather than a single String.

        Map map = new HashMap();
        List attributes = new ArrayList();
        attributes.add("name");
        attributes.add("address");
        map.put(Person.class, attributes);
        marshaller.setUseAttributeFor(map); // Sets both attributes for Person.class

        Hope it helps,
        ranMa

        Show
        ranma172 Frank Martin added a comment - Hello, I was creating my own XStreamMarshaller but I discovered there is already one in Spring. However, I've seen a problem with the method setUseAttributeFor(Map attributes). Map interface says "A map cannot contain duplicate keys". That means you can't set two attribute names for the same class or two classes for the same attribute name. For example, with XStream you can set two attributes for some class: xstream.useAttributeFor(Person.class, "name"); xstream.useAttributeFor(Person.class, "address"); But you can't do it with setUseAttributeFor(Map) because: Map map = new HashMap(); map.put(Person.class, "name"); map.put(Person.class, "address"); // Overwrites the previous value of Person.class key !!! marshaller.setUseAttributeFor(map); // Only sets attribute "address" !!! Here's one example solution. Map values could be a List of Strings (containing all the attributes) rather than a single String. Map map = new HashMap(); List attributes = new ArrayList(); attributes.add("name"); attributes.add("address"); map.put(Person.class, attributes); marshaller.setUseAttributeFor(map); // Sets both attributes for Person.class Hope it helps, ranMa
        Hide
        brownn Neil Brown added a comment -

        For the benefit of anyone that comes across this closed issue, a separate issue has been been raised to address the point raised by Frank Martin above, namely adding support for configuring XStream to use multiple attributes for the same class. See SPR-7636.

        Show
        brownn Neil Brown added a comment - For the benefit of anyone that comes across this closed issue, a separate issue has been been raised to address the point raised by Frank Martin above, namely adding support for configuring XStream to use multiple attributes for the same class. See SPR-7636 .

          People

          • Assignee:
            arjen.poutsma Arjen Poutsma
            Reporter:
            tbrauncajs Tomek Brauncajs
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: