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

The name "" is not legal for JDOM/XML namespaces exception in Spring-WS

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Minor
    • Resolution: Works as Designed
    • Affects Version/s: 1.5.6, 1.5.9
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Environment:
      Unix, Windows, JVM 1.6.x, Weblogic 10.3

      Description

      This problem is similar to the one raised at https://jira.springframework.org/browse/SWS-497. However, I do believe that the issue is caused by Spring, not JDOM. Since I couldn't track the problem down in the Spring-WS source code, my opinion is based on the outcome of a 'trial and error' exercise.

      Here is the exception I'm getting:

      org.jdom.IllegalNameException: The name "" is not legal for JDOM/XML namespaces: Namespace URIs must be non-null and non-empty Strings.
              at org.jdom.Namespace.getNamespace(Namespace.java:162)
              at org.jdom.input.SAXHandler.startPrefixMapping(SAXHandler.java:498)
              at org.xml.sax.helpers.XMLFilterImpl.startPrefixMapping(XMLFilterImpl.java:490)
              at org.jdom.transform.JDOMResult$DocumentBuilder.startPrefixMapping(JDOMResult.java:529)
              at weblogic.apache.xalan.transformer.TransformerIdentityImpl.startPrefixMapping(TransformerIdentityImpl.java:939)
              at weblogic.apache.xml.utils.TreeWalker.startNode(TreeWalker.java:358)
              at weblogic.apache.xml.utils.TreeWalker.traverse(TreeWalker.java:190)
              at weblogic.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:335)
              at org.springframework.xml.transform.TransformerObjectSupport.transform(TransformerObjectSupport.java:71)

      I carried out a number of tests in the Weblogic 10.3 container against a Spring-WS SOAP service. I initially thought that the problem is caused by the javax.xml.soap.MessageFactory setting in JVM. However, I couldn't get satisfactory results after experimenting with various implementation.

      Fortunately, I discovered that the problem can be fixed by declaring the following Spring bean amongst the others in my application:

      <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
          <property name="messageFactory">
              <bean class="weblogic.xml.saaj.MessageFactoryImpl"/>
          </property>
      </bean>

      Moreover, when I swap the configuration with an alternative one, for example:

      <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
          <property name="messageFactory">
              <bean class="com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl"/>
          </property>
      </bean>

      ... the problem is apparent again. It is happening regardless of having JVM started with -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl. Changing the javax.xml.transform.TransformerFactory JVM setting doesn't help either.

      The evidence I presented above clearly indicates that Spring is doing something under the hood that somehow affects the JDOM functionality.

      I replicated the problem in Spring-WS 1.5.6 and 1.5.9 and haven't tested the versions in between.

        Issue Links

          Activity

          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Added formatting

          Show
          arjen.poutsma Arjen Poutsma added a comment - Added formatting
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Thanks for your investigation!

          If I understand correctly, the exception no longer occurs when you use the WebLogic SAAJ MessageFactory. Thus, I would argue that that indicates that Spring is doing nothing under the hood that affects JDOM, but rather it seems to be a problem that occurs when using the SUN SAAJ implementation and JDOM.

          As I've shown in SWS-497, it is possible to get this exception when using plain JDOM and SAAJ APIs. To me, that still shows that it's either a JDOM bug, a SUN SAAJ bug, or possibly both.

          I would love to solve this issue, but I'm afraid there isn't much I can do about it.

          Show
          arjen.poutsma Arjen Poutsma added a comment - Thanks for your investigation! If I understand correctly, the exception no longer occurs when you use the WebLogic SAAJ MessageFactory. Thus, I would argue that that indicates that Spring is doing nothing under the hood that affects JDOM, but rather it seems to be a problem that occurs when using the SUN SAAJ implementation and JDOM. As I've shown in SWS-497 , it is possible to get this exception when using plain JDOM and SAAJ APIs. To me, that still shows that it's either a JDOM bug, a SUN SAAJ bug, or possibly both. I would love to solve this issue, but I'm afraid there isn't much I can do about it.
          Hide
          rzacz Robert Z. added a comment -

          But how would you explain the fact the probelm is also present if I start JVM with -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl and without declaring the messageFactory bean in my application?

          Since -D option affects the whole JVM, I wouldn't point at SUN implementation in this case.

          Show
          rzacz Robert Z. added a comment - But how would you explain the fact the probelm is also present if I start JVM with -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl and without declaring the messageFactory bean in my application? Since -D option affects the whole JVM, I wouldn't point at SUN implementation in this case.
          Hide
          rzacz Robert Z. added a comment - - edited

          I managed to track the problem down and found the cause.

          When Spring bean initialisation takes place via org.springframework.web.servlet.FrameworkServlet#initServletBean -> org.springframework.ws.transport.http.MessageDispatcherServlet#initFrameworkServlet, which then uses org.springframework.ws.support.DefaultStrategiesHelper in order to initialise a default org.springframework.ws.soap.saaj.SaajSoapMessageFactory bean, the ‘afterPropertiesSet’ method is called on the SaajSoapMessageFactory.

          In this default initialisation, the first IF statement of the ‘afterPropertiesSer()’ method is executed:

                          if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
                              if (!StringUtils.hasLength(messageFactoryProtocol)) {
                                  messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL;
                              }
                              if (logger.isInfoEnabled()) {
                                  logger.info("Creating SAAJ 1.3 MessageFactory with " + messageFactoryProtocol);
                              }
                              messageFactory = MessageFactory.newInstance(messageFactoryProtocol);
                          }
                          else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) {
                              logger.info("Creating SAAJ 1.2 MessageFactory");
                              messageFactory = MessageFactory.newInstance();
                          }
                          else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) {
                              logger.info("Creating SAAJ 1.1 MessageFactory");
                              messageFactory = MessageFactory.newInstance();
                          }
                          else {
                              throw new IllegalStateException(
                                      "SaajSoapMessageFactory requires SAAJ 1.1, which was not found on the classpath");
                          }

          Since the ‘messageFactoryProtocol’ class property hasn’t been set, it defaults to SOAPConstants.SOAP_1_1_PROTOCOL. When the MessageFactory.newInstance(messageFactoryProtocol) is called, it internally uses javax.xml.soap.SAAJMetaFactory to create an instance of a new MessageFactory object as opposed to the MessageFactory.newInstance() method without any parameters which uses FactoryFinder.find(MESSAGE_FACTORY_PROPERTY) instead.

          Therefore, because I set only -Djavax.xml.soap.MessageFactory in the WL start-up script, Spring does not actually use it because the first IF statement is satisfied. But if I add -Djavax.xml.soap.MetaFactory=weblogic.xml.saaj.SAAJMetaFactoryImpl everything works fine.

          I also realised that the saaj-impl.jar file (version 1.3) was deployed inside my application’s WAR file. The file contains the ‘META-INF/services’ folder with declared implementations of javax.xml.soap.MetaFactory and javax.xml.soap.MessageFactory. After excluding the file from the WAR file and leaving only -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl for JVM, there was no need to define the ‘messageFactory’ Spring bean anymore. However, I would advice to keep both options to ensure the right implementations are used as the final outcome depends on which ‘newInstance’ method of the MessageFactory is called.

          Although the problem is solved now, I still don’t understand why JDOM was complaining as it doesn’t seem to have a dependency on SAAJ. Probably it wasn’t happy with the input data it was provided with.

          I’ve got only one more question to Arjen: Why does the above code set messageFactoryProtocol to SOAP 1.1 instead of 1.2 when SAAJ 1.3 is found in the first IF statement and the value hasn’t been set before?

          Show
          rzacz Robert Z. added a comment - - edited I managed to track the problem down and found the cause. When Spring bean initialisation takes place via org.springframework.web.servlet.FrameworkServlet#initServletBean -> org.springframework.ws.transport.http.MessageDispatcherServlet#initFrameworkServlet, which then uses org.springframework.ws.support.DefaultStrategiesHelper in order to initialise a default org.springframework.ws.soap.saaj.SaajSoapMessageFactory bean, the ‘afterPropertiesSet’ method is called on the SaajSoapMessageFactory. In this default initialisation, the first IF statement of the ‘afterPropertiesSer()’ method is executed: if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) { if (!StringUtils.hasLength(messageFactoryProtocol)) { messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL; } if (logger.isInfoEnabled()) { logger.info("Creating SAAJ 1.3 MessageFactory with " + messageFactoryProtocol); } messageFactory = MessageFactory.newInstance(messageFactoryProtocol); } else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) { logger.info("Creating SAAJ 1.2 MessageFactory"); messageFactory = MessageFactory.newInstance(); } else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) { logger.info("Creating SAAJ 1.1 MessageFactory"); messageFactory = MessageFactory.newInstance(); } else { throw new IllegalStateException( "SaajSoapMessageFactory requires SAAJ 1.1, which was not found on the classpath"); } Since the ‘messageFactoryProtocol’ class property hasn’t been set, it defaults to SOAPConstants.SOAP_1_1_PROTOCOL. When the MessageFactory.newInstance(messageFactoryProtocol) is called, it internally uses javax.xml.soap.SAAJMetaFactory to create an instance of a new MessageFactory object as opposed to the MessageFactory.newInstance() method without any parameters which uses FactoryFinder.find(MESSAGE_FACTORY_PROPERTY) instead. Therefore, because I set only -Djavax.xml.soap.MessageFactory in the WL start-up script, Spring does not actually use it because the first IF statement is satisfied. But if I add -Djavax.xml.soap.MetaFactory=weblogic.xml.saaj.SAAJMetaFactoryImpl everything works fine. I also realised that the saaj-impl.jar file (version 1.3) was deployed inside my application’s WAR file. The file contains the ‘META-INF/services’ folder with declared implementations of javax.xml.soap.MetaFactory and javax.xml.soap.MessageFactory. After excluding the file from the WAR file and leaving only -Djavax.xml.soap.MessageFactory=weblogic.xml.saaj.MessageFactoryImpl for JVM, there was no need to define the ‘messageFactory’ Spring bean anymore. However, I would advice to keep both options to ensure the right implementations are used as the final outcome depends on which ‘newInstance’ method of the MessageFactory is called. Although the problem is solved now, I still don’t understand why JDOM was complaining as it doesn’t seem to have a dependency on SAAJ. Probably it wasn’t happy with the input data it was provided with. I’ve got only one more question to Arjen: Why does the above code set messageFactoryProtocol to SOAP 1.1 instead of 1.2 when SAAJ 1.3 is found in the first IF statement and the value hasn’t been set before?

            People

            • Assignee:
              arjen.poutsma Arjen Poutsma
              Reporter:
              rzacz Robert Z.
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: