Announcement Announcement Module
Collapse
No announcement yet.
Spring 3.0.1 Release Media Type issue - Spring Team Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring 3.0.1 Release Media Type issue - Spring Team

    Hi

    I have begun using the Spring 3.0.1 maintainence release and have noticed an issue with the org.springframework.http.MediaType class.

    I had a bean definition of:

    Code:
    <bean id="htmlMediaType" class="org.springframework.http.MediaType">
        <constructor-arg value="text/html" />
    </bean>
    This bean was working successfully on Spring 3.0.0 Release but is now causing an issue. I am getting the following Exception:

    Code:
    Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.http.MediaType]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Invalid token character '/' in token "text/html"
    	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
    	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:107)
    	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:273)
    	... 39 more
    Caused by: java.lang.IllegalArgumentException: Invalid token character '/' in token "text/html"
    After looking at the code for the MediaType class however the check token method seems ok:

    Code:
    /**
    	 * Checks the given token string for illegal characters, as defined in RFC 2616, section 2.2.
    	 *
    	 * @throws IllegalArgumentException in case of illegal characters
    	 * @see <a href="http://tools.ietf.org/html/rfc2616#section-2.2">HTTP 1.1, section 2.2</a>
    	 */
    	private void checkToken(String s) {
    		for (int i=0; i < s.length(); i++ ) {
    			char ch = s.charAt(i);
    			if (!TOKEN.get(ch)) {
    				throw new IllegalArgumentException("Invalid token character '" + ch + "' in token \"" + s + "\"");
    			}
    		}
    	}
    The class defines the available seperators as:

    Code:
    BitSet separators = new BitSet(128);
    separators.set('(');
    separators.set(')');
    separators.set('<');
    separators.set('>');
    separators.set('@');
    separators.set(',');
    separators.set(';');
    separators.set(':');
    separators.set('\\');
    separators.set('\"');
    separators.set('/');
    separators.set('[');
    separators.set(']');
    separators.set('?');
    separators.set('=');
    separators.set('{');
    separators.set('}');
    separators.set(' ');
    separators.set('\t');
    The forward slash seems to be in there so I'm not too sure why this exception is now being thrown?

    Any ideas ??

    Eggsy

  • #2
    AndNot

    Hi,

    Could it be because of the following line:

    Code:
    TOKEN.andNot(separators);
    Should this be:
    Code:
    TOKEN.add(seperators)?

    Comment


    • #3
      Basically, the single-string constructor is there for constructing a media type with a '*' subtype. So in effect,

      Code:
      <bean id="htmlMediaType" class="org.springframework.http.MediaType">
          <constructor-arg value="text/html" />
      </bean>
      constructs a media type with type 'text/html' and subtype '*', which is probably not what you want. This behavior was also present in 3.0.0, we just didn't check for '/' before.

      What you want to use is the 2 string constructor, like so:
      Code:
      <bean id="htmlMediaType" class="org.springframework.http.MediaType">
          <constructor-arg value="text"/>
          <constructor-arg value="html"/>
      </bean>
      or use the parseMediaType factory method:
      Code:
      <bean id="htmlMediaType" class="org.springframework.http.MediaType" factoryMethod="parseMediaType">
          <constructor-arg value="text/html" />
      </bean>
      Also note that there is a MediaTypeEditor property editor present in Spring (which uses the parseMediaType method), so if you just want to inject a media type in another bean, you can just inject the string and Spring will do the conversion for you.

      Comment


      • #4
        Thanks

        Hi Arjen

        Oh right so was in fact it was actually an error in my code from the previous version.

        Thanks for the prompt response and description.

        Comment


        • #5
          FYI, thanks for this thread! In case anyone is reading this and attempting with Spring 3, you might get:

          Code:
          java.lang.IllegalArgumentException: Invalid token character '/' in token "text/html"
          	at org.springframework.http.MediaType.checkToken(MediaType.java:282)
          	at org.springframework.http.MediaType.<init>(MediaType.java:254)
          	at org.springframework.http.MediaType.<init>(MediaType.java:207)
          	at org.springframework.http.MediaType.<init>(MediaType.java:196)
          Use this other constructor instead:
          Code:
          <bean id="htmlMediaType" class="org.springframework.http.MediaType">
          		<constructor-arg value="text" />
          		<constructor-arg value="html" />
          	</bean>
          Referring to this thread post, thanks : http://forum.springsource.org/showth...nt+negotiation

          Comment


          • #6
            One quick other note... I removed the "ignoreAcceptHeader" attribute and now code I'm using to experiment with REST works fine if you follow that mechanism too.

            So either using customers.xml as the URI, or using customers with the Accept: header set to application/json or application/xml, for example, works for me.

            Here's some Groovy code to use RESTClient to hack with a restful call...

            Code:
            @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.5.0' )
            import groovyx.net.http.RESTClient
            import groovy.util.slurpersupport.GPathResult
            
            def customers = new RESTClient( 'http://localhost:8080/demo/')
            def results = customers.get (path : 'customers',
               headers: [Accept : 'application/xml', "Accept-Encoding" : 'gzip,deflate'])
            
            println results.data
            
            // if this were XML you could do:
            results.data.customer.each { c ->
              println "customer:  $c.id, $c.firstname $c.lastname"
            }
            
            // and you can set the Accept header to 'application/json', etc...

            Comment

            Working...
            X