Monday, August 10, 2015

cvc-elt.1: Cannot find the declaration of element 'beans'-Part2

In our previous series of the exception cvc-elt.1: Cannot find the declaration of element 'beans' We saw what is xml namespace uri and what is xml namespace prefix.And we resolve a flavor of the exception.Here in this blog we will see other favors of the same exception and measures to avoid it.Before knowing all this we should know how the application context xml document is interpreted by JAVA xml Parser and what are the different components of the application context.

Sample xml configuration:


<xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:task="http://www.springframework.org/schema/task"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                      http://www.springframework.org/schema/task
                      http://www.springframework.org/schema/task/spring-task-3.1.xsd
                      http://www.springframework.org/schema/context
                      http://www.springframework.org/schema/context/spring-context-3.1.xsd ">
Have a look at xsi:schemaLocation.This is used by JAVA xml Parser to validate the xml file.Suppose we have a tag defined in application context  like "context" .For this we have to declare the context namespace.Now what Java xml parser will  here.It will read the  schemaLocation of "context" element as http://www.springframework.org/schema/context/spring-context-3.1.xsd.And try load them from internet to validate the xml file.And Spring intercepts these load requests  and try to find the same xsd version from its own classpath.
Let's do a little bit more analysis.When we build a war or jar file to deploy in production machine, a spring.schemas property  file is created inside the META-INF folder.The contents of the spring.schemas look like this.


Sample Spring.schemas:


http\://www.springframework.org/schema/context/spring-context-2.5.xsd=
org/springframework/context/config/spring-context-2.5.xsd

http\://www.springframework.org/schema/context/spring-context-3.0.xsd=
org/springframework/context/config/spring-context-3.0.xsd

http\://www.springframework.org/schema/context/spring-context-3.1.xsd=
org/springframework/context/config/spring-context-3.1.xsd

http\://www.springframework.org/schema/context/spring-context.xsd=
org/springframework/context/config/spring-context-3.1.xsd

http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=
org/springframework/ejb/config/spring-jee-2.0.xsd

http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=
org/springframework/ejb/config/spring-jee-2.5.xsd

http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=
org/springframework/ejb/config/spring-jee-3.0.xsd

http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=
org/springframework/ejb/config/spring-jee-3.1.xsd

http\://www.springframework.org/schema/jee/spring-jee.xsd=
org/springframework/ejb/config/spring-jee-3.1.xsd

http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=
org/springframework/scripting/config/spring-lang-2.0.xsd

http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=
org/springframework/scripting/config/spring-lang-2.5.xsd

http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=
org/springframework/scripting/config/spring-lang-3.0.xsd

http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=
org/springframework/scripting/config/spring-lang-3.1.xsd

http\://www.springframework.org/schema/lang/spring-lang.xsd=
org/springframework/scripting/config/spring-lang-3.1.xsd

http\://www.springframework.org/schema/task/spring-task-3.0.xsd=
org/springframework/scheduling/config/spring-task-3.0.xsd

http\://www.springframework.org/schema/task/spring-task-3.1.xsd=
org/springframework/scheduling/config/spring-task-3.1.xsd

http\://www.springframework.org/schema/task/spring-task.xsd=
org/springframework/scheduling/config/spring-task-3.1.xsd

http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=
org/springframework/cache/config/spring-cache-3.1.xsd

http\://www.springframework.org/schema/cache/spring-cache.xsd=
org/springframework/cache/config/spring-cache-3.1.xsd
When  we start our application by starting our application server (tomcat/jetty etc) or by simply running the main method,then it takes a schemaLocation value from our application context xml document and try to find the mapping for it in spring.schemas property file.If it finds one in the spring.schemas property file ,then it uses the value associated with this mapping.Usually the value is the location of the corsponding  xsd file.

Let's analyze some rows in spring.schemas property file.

http\://www.springframework.org/schema/context/spring-context-2.5.xsd
=org/springframework/context/config/spring-context-2.5.xsd

http\://www.springframework.org/schema/context/spring-context-3.0.xsd
=org/springframework/context/config/spring-context-3.0.xsd

http\://www.springframework.org/schema/context/spring-context.xsd=
org/springframework/context/config/spring-context-3.0.xsd
Here the left side represents the schemaLocation values as declared in application context xml document.And the right side represents the excat location of the corresponding xsd file.That is if we un jar the spring-context.jar file we will see the corresponding xsd file inside  the package
org.springframework.context.config
After getting the xsd file in the classpath(inside the spring-context.jar),the xml parser validates the tags in the application context document with the corresponding xsd file.

Note:If you are curious about the extra backslash(\) before the : in 
http\://www.springframework.org/schema/context/spring-context-2.5.xsd
Then note that the ':' character is a valid delimiter in the Java properties format, and so the ':' character in the URI needs to be escaped with a backslash.

Now come back to the contents of the spring.schemas property file

http\://www.springframework.org/schema/context/spring-context-2.5.xsd
=org/springframework/context/config/spring-context-2.5.xsd

http\://www.springframework.org/schema/context/spring-context-3.0.xsd
=org/springframework/context/config/spring-context-3.0.xsd

http\://www.springframework.org/schema/context/spring-context.xsd=
org/springframework/context/config/spring-context-3.0.xsd
This means that (in xsi:schemaLocation)   of application context xml document

http://www.springframework.org/schema/context/spring-context-2.5.xsd   
will be validtaed against
org/springframework/context/config/spring-context-2.5.xsd  
in the classpath
And
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
and
http://www.springframework.org/schema/context/spring-context.xsd
will be validated against org/springframework/context/config/spring-context-3.0.xsd
in the classpath

Rule Of Thumb :

Always make sure the xsd version in application context xml document matches with xsd version availble in spring.schemas property file(which is inside META-INF).If we use in application context xml document a higher version  of xsd file and our application contains a lower version of the corresponding  jar file,then mismatch will be there.

But how it resolves the same when there is internet in the machine where application is deployed?
After searching the  class path,if Java xml Parser can't find the same version of the xsd file in the classpath, then it tries to look it over internet.So we get the exception in the machine where internet connection is not there.

Issue with jar creation in Eclipse:

Recently I was creating a jar for a spring application in STS 3.6.Here my application context xml document contains the same version of the xsd file as with my jar file.I matched everything .But still I was getting the same exception cvc-elt.1: Cannot find the declaration of element 'beans'.After digging a little I came to find that,the spring.schemas property file didn't contain any schemaLocation and it's corrsponding xsd file location mapping for 'bean' element.You can see this in sample spring.schemas header.So I copy paste the mapping for the same from another file in spring.schemas property file.Then it started working.So be careful when creating a runnable jar in eclipse. 


 


No comments:

Post a Comment