You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Miguel Feitosa <jr...@gmail.com> on 2011/11/30 22:38:40 UTC

causes exception due to immutable Map being used in JAXBElementProvider

Hello,

I am using CXF-2.5.0 to output REST and SOAP services from the same SEI.

My setup is straight cxf-2.5.0 with jdk1.7.0_01.

It seems there are significant differences from JAXB version 2.0 included
in jdk1.6 and JAXB version 2.1 included in jdk1.7.0 and JAXB version 2.2
shipped with CXF-2.5.0.
These version changes have significant affects on the  xml/json output of
REST services that I am trying to control. For example: REST calls can now
be wrapped, although the name in @XMLElementWrapper annotation is not used
yet.

To side step these version issues I updated from jdk1.6 to jdk1.7.0_01.

I was trying to set a specific namespace prefix for a qualified REST xml.

I configured beans.xml and included package-info.java as below:

@javax.xml.bind.annotation.XmlSchema(    namespace=GoldenKey.NS,
                                        elementFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
                                        attributeFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED,

xmlns={@javax.xml.bind.annotation.XmlNs(prefix = GoldenKey.NS_QUALIFIER ,
namespaceURI=GoldenKey.NS)}
                                     )

package com.upmc.tdc.xml;


beans.xml snippets:

     <jaxrs:server id="goldenKey_rest" address="/rest">
       <jaxrs:serviceBeans>
         <ref bean="goldenKey_bean" />
       </jaxrs:serviceBeans>
        <jaxrs:extensionMappings>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </jaxrs:extensionMappings>
         <jaxrs:providers>
          <ref bean="dateProvider" />
          <ref bean="exceptionMapper" />
          <ref bean="jaxbProvider" />
        </jaxrs:providers>
     </jaxrs:server>

     <jaxws:endpoint serviceName="GoldenKey" endpointName="GoldenKeyPort"
id="goldenKey_soap" implementor="#goldenKey_bean" address="/soap">
        <jaxws:binding>
            <soap:soapBinding version="1.2" />
        </jaxws:binding>
        <jaxws:features>
            <bean class="org.apache.cxf.feature.LoggingFeature">
                <property name="prettyLogging" value="true" />
            </bean>
        </jaxws:features>
    </jaxws:endpoint>

     <bean id="goldenKey_bean" class="com.upmc.tdc.server.GoldenKeyImpl"/>
     <bean id="dateProvider"
class="com.upmc.tdc.server.parameterhandler.DateParameterHandler"/>
     <bean id="exceptionMapper"
class="com.upmc.tdc.exception.ExceptionMapper"/>

     <bean id="jaxbProvider"
class="org.apache.cxf.jaxrs.provider.JAXBElementProvider">
        <property name="marshallerProperties" ref="propertiesMap" />
         <property name="namespacePrefixes" ref="namespaceMap" />
        <property name="enableBuffering" value="true" />
    </bean>

     <util:map id="propertiesMap">
        <entry key="jaxb.formatted.output">
            <value type="java.lang.Boolean">true</value>
            <!--  prints indented XML for REST, useful for testing, can be
disabled for production -->
        </entry>
    </util:map>

    <util:map id="namespaceMap">
        <entry key="http://server.tdc.upmc.com/"  value="GoldenKey"/>
    </util:map>

This setup throws the following exception:

java.lang.UnsupportedOperationException
    at java.util.AbstractMap.put(AbstractMap.java:203)
    at java.util.AbstractMap.putAll(AbstractMap.java:273)
    at
org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollectionMember(JAXBElementProvider.java:327)
    at
org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollection(JAXBElementProvider.java:293)
    at
org.apache.cxf.jaxrs.provider.JAXBElementProvider.writeTo(JAXBElementProvider.java:232)
    at
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:257)
    at
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:144)
    at
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:83)
    at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
<clipped>

Lines 325-330 of JAXBElementProvider.java contain the following code:
        if (ns.length() > 0) {
            Map<String, String> map = Collections.singletonMap(ns, "ns1");
            map.putAll(nsPrefixes);
            setNamespaceMapper(ms, map);
        }
        marshal(obj, cls, genericType, enc, os, mt, ms);

The call Collections.singletonMap(...) is below:

 /**
     * Returns an immutable map, mapping only the specified key to the
     * specified value.  The returned map is serializable.
     *
     * @param key the sole key to be stored in the returned map.
     * @param value the value to which the returned map maps <tt>key</tt>.
     * @return an immutable map containing only the specified key-value
     *         mapping.
     * @since 1.3
     */
    public static <K,V> Map<K,V> singletonMap(K key, V value) {
        return new SingletonMap<>(key, value);
    }

So it seems that
            map.putAll(nsPrefixes);

should fail as it is failing when called because the map is immutable.

In case there are other prefixes to add it seems that the map should be of
another type....

Thank you,
Miguel M Feitosa Jr.

Re: causes exception due to immutable Map being used in JAXBElementProvider

Posted by Daniel Kulp <dk...@apache.org>.
On Wednesday, November 30, 2011 4:38:40 PM Miguel Feitosa wrote:
> Lines 325-330 of JAXBElementProvider.java contain the following code:
>         if (ns.length() > 0) {
>             Map<String, String> map = Collections.singletonMap(ns, "ns1");
>             map.putAll(nsPrefixes);
>             setNamespaceMapper(ms, map);
>         }
>         marshal(obj, cls, genericType, enc, os, mt, ms);
> 
> The call Collections.singletonMap(...) is below:
> 
>  /**
>      * Returns an immutable map, mapping only the specified key to the
>      * specified value.  The returned map is serializable.
>      *
>      * @param key the sole key to be stored in the returned map.
>      * @param value the value to which the returned map maps <tt>key</tt>.
>      * @return an immutable map containing only the specified key-value
>      *         mapping.
>      * @since 1.3
>      */
>     public static <K,V> Map<K,V> singletonMap(K key, V value) {
>         return new SingletonMap<>(key, value);
>     }
> 
> So it seems that
>             map.putAll(nsPrefixes);
> 
> should fail as it is failing when called because the map is immutable.
> 
> In case there are other prefixes to add it seems that the map should be of
> another type....

That DEFINITELY looks like a bug to me.   Can you log that?


-- 
Daniel Kulp
dkulp@apache.org - http://dankulp.com/blog
Talend Community Coder - http://coders.talend.com

Re: causes exception due to immutable Map being used in JAXBElementProvider

Posted by Miguel Martins Feitosa Filho <jr...@gmail.com>.
Ok...

Thank you for your prompt answer and for the pointer.

I understand that it is better for the SEI to return

class ArrayOfBooks {
 public List<Book> getBooks()
}

than it is for the SEI to return

List<Book>

both with the appropriate annotations

Miguel

On Thu, Dec 1, 2011 at 5:11 AM, Sergey Beryozkin <sb...@gmail.com>wrote:

> Hi, thanks for this analysis, it's a copy & paste bug, I did not test the
> application of custom marshaller properties when the explicit collection is
> written out, will fix shortly
>
> If you get a collection such as List<Book> wrapped into Books bean then
> these properties will be applied ok
>
> Sergey
>
> On 30/11/11 21:38, Miguel Feitosa wrote:
>
>> Hello,
>>
>> I am using CXF-2.5.0 to output REST and SOAP services from the same SEI.
>>
>> My setup is straight cxf-2.5.0 with jdk1.7.0_01.
>>
>> It seems there are significant differences from JAXB version 2.0 included
>> in jdk1.6 and JAXB version 2.1 included in jdk1.7.0 and JAXB version 2.2
>> shipped with CXF-2.5.0.
>> These version changes have significant affects on the  xml/json output of
>> REST services that I am trying to control. For example: REST calls can now
>> be wrapped, although the name in @XMLElementWrapper annotation is not used
>> yet.
>>
>> To side step these version issues I updated from jdk1.6 to jdk1.7.0_01.
>>
>> I was trying to set a specific namespace prefix for a qualified REST xml.
>>
>> I configured beans.xml and included package-info.java as below:
>>
>> @javax.xml.bind.annotation.**XmlSchema(    namespace=GoldenKey.NS,
>>                                         elementFormDefault =
>> javax.xml.bind.annotation.**XmlNsForm.QUALIFIED,
>>                                         attributeFormDefault =
>> javax.xml.bind.annotation.**XmlNsForm.QUALIFIED,
>>
>> xmlns={@javax.xml.bind.**annotation.XmlNs(prefix =
>> GoldenKey.NS_QUALIFIER ,
>> namespaceURI=GoldenKey.NS)}
>>                                      )
>>
>> package com.upmc.tdc.xml;
>>
>>
>> beans.xml snippets:
>>
>>      <jaxrs:server id="goldenKey_rest" address="/rest">
>>        <jaxrs:serviceBeans>
>>          <ref bean="goldenKey_bean" />
>>        </jaxrs:serviceBeans>
>>         <jaxrs:extensionMappings>
>>             <entry key="json" value="application/json" />
>>             <entry key="xml" value="application/xml" />
>>         </jaxrs:extensionMappings>
>>          <jaxrs:providers>
>>           <ref bean="dateProvider" />
>>           <ref bean="exceptionMapper" />
>>           <ref bean="jaxbProvider" />
>>         </jaxrs:providers>
>>      </jaxrs:server>
>>
>>      <jaxws:endpoint serviceName="GoldenKey" endpointName="GoldenKeyPort"
>> id="goldenKey_soap" implementor="#goldenKey_bean" address="/soap">
>>         <jaxws:binding>
>>             <soap:soapBinding version="1.2" />
>>         </jaxws:binding>
>>         <jaxws:features>
>>             <bean class="org.apache.cxf.feature.**LoggingFeature">
>>                 <property name="prettyLogging" value="true" />
>>             </bean>
>>         </jaxws:features>
>>     </jaxws:endpoint>
>>
>>      <bean id="goldenKey_bean" class="com.upmc.tdc.server.**
>> GoldenKeyImpl"/>
>>      <bean id="dateProvider"
>> class="com.upmc.tdc.server.**parameterhandler.**DateParameterHandler"/>
>>      <bean id="exceptionMapper"
>> class="com.upmc.tdc.exception.**ExceptionMapper"/>
>>
>>      <bean id="jaxbProvider"
>> class="org.apache.cxf.jaxrs.**provider.JAXBElementProvider">
>>         <property name="marshallerProperties" ref="propertiesMap" />
>>          <property name="namespacePrefixes" ref="namespaceMap" />
>>         <property name="enableBuffering" value="true" />
>>     </bean>
>>
>>      <util:map id="propertiesMap">
>>         <entry key="jaxb.formatted.output">
>>             <value type="java.lang.Boolean">true<**/value>
>>             <!--  prints indented XML for REST, useful for testing, can be
>> disabled for production -->
>>         </entry>
>>     </util:map>
>>
>>     <util:map id="namespaceMap">
>>         <entry key="http://server.tdc.upmc.**com/<http://server.tdc.upmc.com/>"
>>  value="GoldenKey"/>
>>     </util:map>
>>
>> This setup throws the following exception:
>>
>> java.lang.**UnsupportedOperationException
>>     at java.util.AbstractMap.put(**AbstractMap.java:203)
>>     at java.util.AbstractMap.putAll(**AbstractMap.java:273)
>>     at
>> org.apache.cxf.jaxrs.provider.**JAXBElementProvider.**
>> marshalCollectionMember(**JAXBElementProvider.java:327)
>>     at
>> org.apache.cxf.jaxrs.provider.**JAXBElementProvider.**marshalCollection(*
>> *JAXBElementProvider.java:293)
>>     at
>> org.apache.cxf.jaxrs.provider.**JAXBElementProvider.writeTo(**
>> JAXBElementProvider.java:232)
>>     at
>> org.apache.cxf.jaxrs.**interceptor.**JAXRSOutInterceptor.**
>> serializeMessage(**JAXRSOutInterceptor.java:257)
>>     at
>> org.apache.cxf.jaxrs.**interceptor.**JAXRSOutInterceptor.**
>> processResponse(**JAXRSOutInterceptor.java:144)
>>     at
>> org.apache.cxf.jaxrs.**interceptor.**JAXRSOutInterceptor.**handleMessage(
>> **JAXRSOutInterceptor.java:83)
>>     at
>> org.apache.cxf.phase.**PhaseInterceptorChain.**doIntercept(**
>> PhaseInterceptorChain.java:**263)
>> <clipped>
>>
>> Lines 325-330 of JAXBElementProvider.java contain the following code:
>>         if (ns.length()>  0) {
>>             Map<String, String>  map = Collections.singletonMap(ns,
>> "ns1");
>>             map.putAll(nsPrefixes);
>>             setNamespaceMapper(ms, map);
>>         }
>>         marshal(obj, cls, genericType, enc, os, mt, ms);
>>
>> The call Collections.singletonMap(...) is below:
>>
>>  /**
>>      * Returns an immutable map, mapping only the specified key to the
>>      * specified value.  The returned map is serializable.
>>      *
>>      * @param key the sole key to be stored in the returned map.
>>      * @param value the value to which the returned map maps<tt>key</tt>.
>>      * @return an immutable map containing only the specified key-value
>>      *         mapping.
>>      * @since 1.3
>>      */
>>     public static<K,V>  Map<K,V>  singletonMap(K key, V value) {
>>         return new SingletonMap<>(key, value);
>>     }
>>
>> So it seems that
>>             map.putAll(nsPrefixes);
>>
>> should fail as it is failing when called because the map is immutable.
>>
>> In case there are other prefixes to add it seems that the map should be of
>> another type....
>>
>> Thank you,
>> Miguel M Feitosa Jr.
>>
>>
>
> --
> Sergey Beryozkin
>
> Talend Community Coders
> http://coders.talend.com/
>
> Blog: http://sberyozkin.blogspot.com
>

Re: causes exception due to immutable Map being used in JAXBElementProvider

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi, thanks for this analysis, it's a copy & paste bug, I did not test 
the application of custom marshaller properties when the explicit 
collection is written out, will fix shortly

If you get a collection such as List<Book> wrapped into Books bean then 
these properties will be applied ok

Sergey
On 30/11/11 21:38, Miguel Feitosa wrote:
> Hello,
>
> I am using CXF-2.5.0 to output REST and SOAP services from the same SEI.
>
> My setup is straight cxf-2.5.0 with jdk1.7.0_01.
>
> It seems there are significant differences from JAXB version 2.0 included
> in jdk1.6 and JAXB version 2.1 included in jdk1.7.0 and JAXB version 2.2
> shipped with CXF-2.5.0.
> These version changes have significant affects on the  xml/json output of
> REST services that I am trying to control. For example: REST calls can now
> be wrapped, although the name in @XMLElementWrapper annotation is not used
> yet.
>
> To side step these version issues I updated from jdk1.6 to jdk1.7.0_01.
>
> I was trying to set a specific namespace prefix for a qualified REST xml.
>
> I configured beans.xml and included package-info.java as below:
>
> @javax.xml.bind.annotation.XmlSchema(    namespace=GoldenKey.NS,
>                                          elementFormDefault =
> javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
>                                          attributeFormDefault =
> javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
>
> xmlns={@javax.xml.bind.annotation.XmlNs(prefix = GoldenKey.NS_QUALIFIER ,
> namespaceURI=GoldenKey.NS)}
>                                       )
>
> package com.upmc.tdc.xml;
>
>
> beans.xml snippets:
>
>       <jaxrs:server id="goldenKey_rest" address="/rest">
>         <jaxrs:serviceBeans>
>           <ref bean="goldenKey_bean" />
>         </jaxrs:serviceBeans>
>          <jaxrs:extensionMappings>
>              <entry key="json" value="application/json" />
>              <entry key="xml" value="application/xml" />
>          </jaxrs:extensionMappings>
>           <jaxrs:providers>
>            <ref bean="dateProvider" />
>            <ref bean="exceptionMapper" />
>            <ref bean="jaxbProvider" />
>          </jaxrs:providers>
>       </jaxrs:server>
>
>       <jaxws:endpoint serviceName="GoldenKey" endpointName="GoldenKeyPort"
> id="goldenKey_soap" implementor="#goldenKey_bean" address="/soap">
>          <jaxws:binding>
>              <soap:soapBinding version="1.2" />
>          </jaxws:binding>
>          <jaxws:features>
>              <bean class="org.apache.cxf.feature.LoggingFeature">
>                  <property name="prettyLogging" value="true" />
>              </bean>
>          </jaxws:features>
>      </jaxws:endpoint>
>
>       <bean id="goldenKey_bean" class="com.upmc.tdc.server.GoldenKeyImpl"/>
>       <bean id="dateProvider"
> class="com.upmc.tdc.server.parameterhandler.DateParameterHandler"/>
>       <bean id="exceptionMapper"
> class="com.upmc.tdc.exception.ExceptionMapper"/>
>
>       <bean id="jaxbProvider"
> class="org.apache.cxf.jaxrs.provider.JAXBElementProvider">
>          <property name="marshallerProperties" ref="propertiesMap" />
>           <property name="namespacePrefixes" ref="namespaceMap" />
>          <property name="enableBuffering" value="true" />
>      </bean>
>
>       <util:map id="propertiesMap">
>          <entry key="jaxb.formatted.output">
>              <value type="java.lang.Boolean">true</value>
>              <!--  prints indented XML for REST, useful for testing, can be
> disabled for production -->
>          </entry>
>      </util:map>
>
>      <util:map id="namespaceMap">
>          <entry key="http://server.tdc.upmc.com/"  value="GoldenKey"/>
>      </util:map>
>
> This setup throws the following exception:
>
> java.lang.UnsupportedOperationException
>      at java.util.AbstractMap.put(AbstractMap.java:203)
>      at java.util.AbstractMap.putAll(AbstractMap.java:273)
>      at
> org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollectionMember(JAXBElementProvider.java:327)
>      at
> org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollection(JAXBElementProvider.java:293)
>      at
> org.apache.cxf.jaxrs.provider.JAXBElementProvider.writeTo(JAXBElementProvider.java:232)
>      at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:257)
>      at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:144)
>      at
> org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:83)
>      at
> org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
> <clipped>
>
> Lines 325-330 of JAXBElementProvider.java contain the following code:
>          if (ns.length()>  0) {
>              Map<String, String>  map = Collections.singletonMap(ns, "ns1");
>              map.putAll(nsPrefixes);
>              setNamespaceMapper(ms, map);
>          }
>          marshal(obj, cls, genericType, enc, os, mt, ms);
>
> The call Collections.singletonMap(...) is below:
>
>   /**
>       * Returns an immutable map, mapping only the specified key to the
>       * specified value.  The returned map is serializable.
>       *
>       * @param key the sole key to be stored in the returned map.
>       * @param value the value to which the returned map maps<tt>key</tt>.
>       * @return an immutable map containing only the specified key-value
>       *         mapping.
>       * @since 1.3
>       */
>      public static<K,V>  Map<K,V>  singletonMap(K key, V value) {
>          return new SingletonMap<>(key, value);
>      }
>
> So it seems that
>              map.putAll(nsPrefixes);
>
> should fail as it is failing when called because the map is immutable.
>
> In case there are other prefixes to add it seems that the map should be of
> another type....
>
> Thank you,
> Miguel M Feitosa Jr.
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com