MappingExpection NHibernate 4 .net 4.5 SPA - asp.net-mvc

I've tried a 1000 different options an permutations.
Why can't compile my Cat mapping?
Exception thrown: 'NHibernate.MappingException' in NHibernate.dll
Additional information: Could not compile the mapping document: (string)
Configuration cfg = new Configuration();
cfg.Configure();
cfg.AddXmlString(
#"<?xml version=""1.0"" encoding=""utf - 8"" ?>"
+ #"<hibernate-mapping xmlns=""urn:nhibernate-mapping-2.2"" assembly=""QuickStart"" namespace=""QuickStart.Cat"">"
+ #"<class name=""Cat"" table=""Cat"">"
+ #" <id name=""Id"" ><column name=""CatId"" /><generator class=""uuid.hex"" /></id>"
//+ #" <id name=""Id"" ><column name=""CatId"" sql-type=""char(32)"" not-null=""true"" /><generator class=""uuid.hex"" /></id>"
//+ #" <property name=""Name"" ><column name=""Name"" length=""16"" not-null=""true"" /></property>"
//+ #" <property name=""Sex"" />"
//+ #" <property name=""Weight"" />"
+ #"</class>"
+ #"</hibernate-mapping>"
);
--- from Web.Config
NHibernate.Connection.DriverConnectionProvider
NHibernate.Driver.SqlClientDriver
NHibernate.Dialect.MsSql2012Dialect
Server=localhost;initial catalog=PlaygroundDB;Integrated Security=True

encoding=""utf - 8"" ?> should be encoding=""utf-8""?>
But I never add xml mapping programmaticaly one by one. And even less as raw string (which is quite prone to errors). Instead, I add ClassName.hbm.xml files in project, setting their Build action property to Embedded resource, and I call .AddAssembly(MyProjectAssembly) before building the configuration.
If your mappings are embedded in the same assembly defining your session factory, the code is as simple as:
public static class NHibernateSessionFactory
{
private static readonly ISessionFactory _sessionFactory;
static NHibernateSessionFactory()
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(NHibernateSessionFactory).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
public static ISessionFactory Instance { get { return _sessionFactory; } }
}
Minimal configuration file (hibernate.cfg.xml) I am using:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="ProjectName">
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string_name">ProjectConnectionStringName</property>
<property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
<property name="adonet.batch_size">100</property>
<property name="prepare_sql">true</property>
</session-factory>
</hibernate-configuration>
ProjectConnectionStringName refers to a connection string defined in .Net standard configuration connectionStrings node.

Related

Neo4j database not persisting using Spring Data Neo4j

I'm starting a project using Neo4j and Spring Data Neo4j. I want my program to use a local database that already contains my data (as opposed to loading the data each time on startup) since I have a lot of data that needs to be loaded into the database. I've tried setting up a test case that populates a database with my data in order to accomplish this goal. However, the data in the database does not appear to persist after my tests have finished running: I look at the database using the neo4j console/shell and find it is empty.
I've constructed a small example project that's also not working. Any insight into what I'm doing incorrectly would be appreciated.
Node entity class:
#NodeEntity
public class Entity {
#GraphId private Long graphId;
private String name;
public Entity() { }
public Entity(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Repository class:
public interface EntityRepository extends GraphRepository<Entity> { }
My test class:
#ContextConfiguration(locations = "classpath:applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class DatabaseTest {
#Autowired Neo4jTemplate template;
#Autowired EntityRepository entityRepository;
#Test
public void testCreatingEntities() {
Entity entity1 = new Entity("one");
Entity entity2 = new Entity("two");
template.save(entity1);
template.save(entity2);
Iterator<Entity> entityIterator = entityRepository.findAll().iterator();
List<Entity> entityList = IteratorUtils.toList(entityIterator);
System.out.println("Number of entities = " + entityList.size());
for(Entity entity : entityList) {
System.out.println("Entity " + entity.getName());
}
}
}
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:spring-configured/>
<context:annotation-config/>
<context:component-scan base-package="personal.neo4j">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<neo4j:config storeDirectory="data/test.db"
base-package="personal.neo4j"/>
<neo4j:repositories base-package="personal.neo4j"/>
<tx:annotation-driven/>
</beans>
Test output:
Running personal.neo4j.DatabaseTest
Number of entities = 2
Entity one
Entity two
Using libraries:
Java 1.7
Spring 3.2.8.RELEASE
Neo4j 2.0.2
Spring Data Neo4j 3.0.2.RELEASE
JUnit 4.11
Thanks for your help,
Thomas
See if this thread helps:
http://forum.spring.io/forum/spring-projects/data/53804-commit-transactions-running-springjunit4classrunner
Looks like SpringJUnit4ClassRunner will rollback all transactions, unless explicitly told otherwise.

How to Integrate Struts Conventions with Tiles such that the benefit of conventions is maintained

How to Integrate Struts Conventions with Tiles while maintaining conventions benefits?
The issue is that conventions links url-to-action-to-result automatically and does this nicely for jsp, velocity and freemarker results. It does not expect to deal with a tiles result.
When using tiles we typically want all our UI actions (as opposed the json/xml service actions) to use tiles but in doing so we lose the convention for the result component and need to use annotations. Annotations allow us to deviate from the expected, but in a large application when expecting to use tiles this is an annoyance. Further conventions allows us to create actions by only specifying a view. We would want to retain such benefit when using tiles as well. To rectify this we need to establish a convention that carries though to the tiles result such that we don't need to use annotations to tie the action to the tiles result and that we can continue to create JSPs without actions classes which will gain the benefits of conventions (no xml) and the benefits of tiles (all the boiler plate is factored into tiles).
How to achieve this?
This is a self answer to help others who wish to address this issue
Here are the steps needed:
Create custom tiles result which dynamically builds a "location" string (the location string is the value passed to tiles) which takes into account the namespace, actionName.
Create a package which uses this result (named "tiles") and have conventions use that as it's parent package
Implement and register a "com.opensymphony.xwork2.UnknownHandler", this step is the most critical as this handler is called when the result can't be resolved
Tiles definition(s) which make use of "location" passed in from the first step
The above steps require the following in struts.xml
<struts>
<constant name="struts.convention.default.parent.package" value="tiles-package"/>
<bean type="com.opensymphony.xwork2.UnknownHandler" name="tilesUnknownHandler" class="com.kenmcwilliams.tiles.result.TilesUnknownHandler"/>
<package name="tiles-package" extends="convention-default">
<result-types>
<result-type default="true" name="tiles" class="com.kenmcwilliams.tiles.result.TilesResult"/>
</result-types>
</package>
</struts>
Custom result-type implementation:
package com.kenmcwilliams.tiles.result;
import com.opensymphony.xwork2.ActionInvocation;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletDispatcherResult;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.request.servlet.ServletRequest;
import org.apache.tiles.request.servlet.ServletUtil;
public class TilesResult extends ServletDispatcherResult {
private static final Logger log = Logger.getLogger(TilesResult.class.getName());
public TilesResult() {
super();
}
public TilesResult(String location) {
super(location);
}
#Override
public void doExecute(String location, ActionInvocation invocation) throws Exception {
//location = "test.definition"; //for test
log.log(Level.INFO, "TilesResult doExecute() location: {0}", location);
//Start simple conventions
//
if (/** tiles && **/location == null) {
String namespace = invocation.getProxy().getNamespace();
String actionName = invocation.getProxy().getActionName();
location = namespace + "#" + actionName + ".jsp"; //Warning forcing extension
log.log(Level.INFO, "TilesResult namespace: {0}", namespace);
log.log(Level.INFO, "TilesResult actionName: {0}", actionName);
log.log(Level.INFO, "TilesResult location: {0}", location);
}
//End simple conventions
setLocation(location);
ServletContext context = ServletActionContext.getServletContext();
ApplicationContext applicationContext = ServletUtil.getApplicationContext(context);
TilesContainer container = TilesAccess.getContainer(applicationContext);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletRequest servletRequest = new ServletRequest(applicationContext, request, response);
container.render(location, servletRequest);
}
}
TilesUnknownHandler Implementation:
package com.kenmcwilliams.tiles.result;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.config.entities.ResultConfig.Builder;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import flexjson.JSONSerializer;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.convention.ConventionUnknownHandler;
public class TilesUnknownHandler extends ConventionUnknownHandler {
private static final Logger log = Logger.getLogger(TilesUnknownHandler.class.getName());
private static final String conventionBase = "/WEB-INF/content";
#Inject
public TilesUnknownHandler(Configuration configuration, ObjectFactory objectFactory,
ServletContext servletContext, Container container,
#Inject("struts.convention.default.parent.package") String defaultParentPackageName,
#Inject("struts.convention.redirect.to.slash") String redirectToSlash,
#Inject("struts.convention.action.name.separator") String nameSeparator) {
super(configuration, objectFactory, servletContext, container, defaultParentPackageName,
redirectToSlash, nameSeparator);
log.info("Constructed TilesUnknownHandler");
}
#Override
public ActionConfig handleUnknownAction(String namespace, String actionName)
throws XWorkException {
ActionConfig actionConfig;
log.info("TilesUnknownHandler: before handleUnknownAction");
ActionConfig handleUnknownAction = super.handleUnknownAction(namespace, actionName);
log.info("TilesUnknownHandler: after handleUnknownAction, returning with:");
log.log(Level.INFO, "...ActionConfig value: {0}", (new JSONSerializer().serialize(handleUnknownAction)));
log.log(Level.INFO, "Modifying handleUnknowAction result handler");
Map<String, ResultConfig> results = handleUnknownAction.getResults();
ResultConfig resultConfig = results.get("success");
Builder builder = new ResultConfig.Builder("com.opensymphony.xwork2.config.entities.ResultConfig", "com.kenmcwilliams.tiles.result.TilesResult");
Map<String, String> params = resultConfig.getParams();
String tilesResultString = null;
String location = params.get("location");
if (location != null && !location.isEmpty()) {
int length = conventionBase.length();
if(StringUtils.startsWith(location, conventionBase)){
String subString = location.substring(length); //chop off "/WEB-INF/content"
int count = StringUtils.countMatches(subString, "/");//TODO: maybe check for "//", although I don't know why it would be in the string
if (count == 1){//empty namespace
tilesResultString = subString.replaceFirst("/", "#"); //TODO: because I am doing a straight replacement of the last element the else can probably be removed
}else{ //replace the last slash between the namespace and the file with "#"
int lastIndex = subString.lastIndexOf("/");
//subString.substring(lastIndex, lastIndex);
String nameSpace = subString.substring(0, lastIndex);
String file = subString.substring(lastIndex + 1);
tilesResultString = nameSpace + "#" + file;
}
}
}
Map<String, String> myParams = new LinkedHashMap<String, String>();
myParams.put("location", tilesResultString);
builder.addParams(myParams);
ResultConfig build = builder.build();
Map<String, ResultConfig> myMap = new LinkedHashMap<String, ResultConfig>();
myMap.put("success", build);
log.log(Level.INFO, "\n\n...results: {0}\n\n", (new JSONSerializer().serialize(results)));
actionConfig = new ActionConfig.Builder(handleUnknownAction).addResultConfigs(myMap).build();
//className("com.kenmcwilliams.tiles.result.TilesResult")
return actionConfig;
}
#Override
public Result handleUnknownResult(ActionContext actionContext, String actionName,
ActionConfig actionConfig, String resultCode) throws XWorkException {
log.info("TilesUnknownHandler: before handleUnknownResult");
Result handleUnknownResult = super.handleUnknownResult(actionContext, actionName, actionConfig, resultCode);
log.info("TilesUnknownHandler: after handleUnknownResult, returning with:");
log.log(Level.INFO, "...Result value: {0}", (new JSONSerializer().serialize(handleUnknownResult)));
return handleUnknownResult;
}
}
An example of how to use our "location" string which is in the form of: NameSpace + "#" + ActionName + ".jsp", note this definition <definition name="REGEXP:(.*)#(.*)" extends="default"> in the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="default" template="/WEB-INF/template/template.jsp">
<put-list-attribute name="cssList" cascade="true">
<add-attribute value="/style/cssreset-min.css" />
<add-attribute value="/style/cssfonts-min.css" />
<add-attribute value="/style/cssbase-min.css" />
<add-attribute value="/style/grids-min.css" />
<add-attribute value="/script/jquery-ui-1.8.24.custom/css/ui-lightness/jquery-ui-1.8.24.custom.css" />
<add-attribute value="/style/style.css" />
</put-list-attribute>
<put-list-attribute name="jsList" cascade="true">
<add-attribute value="/script/jquery/1.8.1/jquery.min.js" />
<add-attribute value="/script/jquery-ui-1.8.24.custom/js/jquery-ui-1.8.24.custom.min.js" />
<add-attribute value="/script/jquery.sort.js" />
<add-attribute value="/script/custom/jquery-serialize.js" />
</put-list-attribute>
<put-attribute name="title" value="defaults-name" cascade="true" type="string"/>
<put-attribute name="head" value="/WEB-INF/template/head.jsp"/>
<put-attribute name="header" value="/WEB-INF/template/header.jsp"/>
<put-attribute name="body" value="/WEB-INF/template/body.jsp"/>
<put-attribute name="footer" value="/WEB-INF/template/footer.jsp"/>
</definition>
<definition name="REGEXP:(.*)#(.*)" extends="default">
<put-attribute name="title" cascade="true" expression="OGNL:#com.opensymphony.xwork2.ActionContext#getContext().name"/>
<put-attribute name="body" value="/WEB-INF/content{1}/{2}"/>
</definition>
</tiles-definitions>
With this in place you can create JSP's under /WEB-INF/content/someplace/my-action.jsp
Just as you would with conventions AND tiles will decorate it appropriately as well if you create an action class called com.myapp.action.someplace.MyAction without any result type this code will execute and the /WEB-INF/content/someplace/my-action.jsp result would still be rendered.
There you have it conventions + tiles with no more annotations (well for the normal case).
NOTES:
This answer certainly isn't perfect but it does provide a working example of the strategy which can be applied to other view technologies (sitemesh, others).
Currently you can see the ".jsp" is being appended in the tiles result NOT in the tiles definitions this is inflexible. The specific extension should be specified within tiles, that is the body attribute within the definition should append the specific view type (.jsp, .fml, .vm) because you should know best at that time.
It is important to note that definitions are tried in the order they are given,so you can override the normal case REGEXP:(.*)#(.*) by placing definitions between the default and REGEXP:(.*)#(.*) definitions. For instance a definition called authenticated\(.*) can be placed between these two definitions. After all if you couldn't do this and all pages had to be tiled the same we really wouldn't be using tiles!
Just so you know when using tiles3 (the struts2 tiles3 plugin) you can use all three types of view technologies (jsp, freemarker, velocity) to compose one tile. It works. You are probably going to use one view technology consistently but it's nice to know it is possible.

Unable to create Spring.net object from MVC application

I'm building a MVC 4 application with Spring support.
My Web.config looks like following
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
...
<spring>
<context type="Spring.Context.Support.MvcApplicationContext, Spring.Web.Mvc3, Version=1.3.2.40943, Culture=neutral, PublicKeyToken=65e474d141e25e07">
<!--<resource uri="config://spring/objects"/>-->
</context>
<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object type="Org.Zighinetto.MyNS.RepositoryHelper" singleton="true" id="Org.Zighinetto.RepositoryHelper">
<property name="SessionFactory" ref="Org.Zighinetto.SessionFactory"/>
</object>
<object id="Org.Zighinetto.Ecommerce.NHibernateHelper" type="MvcTest.Utils.NHibernateHelper" singleton="true"/>
<object id="Org.Zighinetto.Ecommerce.SessionFactory" type="NHibernate.ISessionFactory" factory-object="Org.Zighinetto.Ecommerce.NHibernateHelper" factory-method="CreateSessionFactory" />
</objects>
</spring>
In my Controller I want to get a reference to that object that basically wraps all FNH DAOs (I called them Repositories...)
public CustomerController()
{
IApplicationContext ctx = new MvcApplicationContext();
RepositoryHelper repoHelper = (RepositoryHelper)ctx.GetObject("Org.Zighinetto.RepositoryHelper");
_customerRepository = repoHelper.CustomerRepository;
}
GetObject call crashes with following exception
No object named 'Org.Zighinetto.RepositoryHelper' is defined : Cannot find definition for object [Org.Zighinetto.RepositoryHelper]
[NoSuchObjectDefinitionException: No object named 'Org.Zighinetto.RepositoryHelper' is defined : Cannot find definition for object [Org.Zighinetto.RepositoryHelper]]
Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure) in c:\_prj\spring-net\trunk\src\Spring\Spring.Core\Objects\Factory\Support\AbstractObjectFactory.cs:2065
Spring.Objects.Factory.Support.AbstractObjectFactory.GetObject(String name) in c:\_prj\spring-net\trunk\src\Spring\Spring.Core\Objects\Factory\Support\AbstractObjectFactory.cs:1826
Spring.Context.Support.AbstractApplicationContext.GetObject(String name) in c:\_prj\spring-net\trunk\src\Spring\Spring.Core\Context\Support\AbstractApplicationContext.cs:1538
Am I initializing Spring.net context bad? What can I do to obtain that object reference?
[Add]
ctx.GetObjectDefinitionNames() returns empty string. So no object has been defined
Initializing AppContext with new MvcApplicationContext("~/Web.Config") doesn't change
I fixed using IApplicationContext ctx = WebApplicationContext.GetRootContext()

Custom validation error messages using Jaxb2marshaller and spring-ws

I have a running spring-ws project that can unmarshal requests using Jax2b, but when unmarshalling of integers/booleans fail I get an error message with little detail and often without the name of the invalid element. E.g.:
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.]
This also becomes the content of the SOAPFault response from my webservice.
I am trying to change the message to include the element name. I'm using a ValidationEventHandler to change the message by throwing a RuntimeException from the event handler, but it only works i some cases.
ValidationEventHandler:
#Component
public class ValidationEventHandlerImpl implements ValidationEventHandler {
#Override
public boolean handleEvent(ValidationEvent event) {
String message = event.getMessage();
String linkedMessage = "";
if(event.getLinkedException() != null)
linkedMessage = event.getLinkedException().toString();
boolean ignoreValidationEvent = true;
if(message.contains("NumberFormatException") ||
message.contains("is not a valid value") ||
linkedMessage.contains("NumberFormatException") ||
linkedMessage.contains("is not a valid value")){
ignoreValidationEvent = false;
}
if(ignoreValidationEvent){
return true;
}else{
String nodeName = "";
if(event.getLocator() != null && event.getLocator().getNode() != null)
nodeName = event.getLocator().getNode().getNodeName();
//This is the important line
throw new RuntimeException("Error parsing '" + nodeName + "': " + event.getMessage());
}
}
}
It successfully changes:
JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: Not a number: 32g321
- with linked exception:
[java.lang.NumberFormatException: Not a number: 32g321]
to: RuntimeException message: "java.lang.RuntimeException: Error parsing 'MyNodeName': Not a number: 32g321"
(Event Severity: ERROR)
But it does not work when I want it to change:
JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; cvc-datatype-valid.1.2.1: '' is not a valid value for 'integer'.]
to: RuntimeException message: "java.lang.RuntimeException: Error parsing 'MyNodeName': '' is not a valid value for 'integer'".
The RuntimeException is ignored and the SAXParseException is thrown instead and added to the SOAPFault reponse.
(Event Severity: FATAL_ERROR)
Spring configuration for Jaxb2Marshalling:
<bean id="jaxb2MarshallerContact" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.oxm.ContactRequest</value>
<value>com.model.oxm.ContactResponse</value>
</list>
</property>
<property name="marshallerProperties">
<map>
<entry>
<key>
<util:constant static-field="javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT" />
</key>
<value type="boolean">true</value>
</entry>
<entry>
<key>
<util:constant static-field="javax.xml.bind.Marshaller.JAXB_FRAGMENT" />
</key>
<value type="boolean">true</value>
</entry>
</map>
</property>
<property name="schema" ref="ContactServiceSchema" />
<property name="validationEventHandler" ref="validationEventHandlerImpl" />
</bean>
<bean id="ContactServiceSchema" class="org.springframework.core.io.ClassPathResource">
<constructor-arg value="WEB-INF/schemas/ContactService.xsd" />
</bean>
Endpoint:
#Endpoint
public class ContactEndpoint {
private Logger logger = Logger.getLogger(ContactEndpoint.class);
#Autowired
private ContactService contactService;
private static final String NAMESPACE_URI = "http://mydomain/schemas";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "ContactRequest")
#ResponsePayload
public ContactResponse handleContactRequest(#RequestPayload ContactRequest contactRequest) throws Exception {
...
How can I return a custom message instead of the SAXParseException message?
Is there a better way of implementing this, e.g. using ValidationErrorHandler?
Thanks!
I finally found a way around this issue. Instead of throwing a new RuntimeException from the ValidationEventHandler, I added it as a suppressed exception on the events linked exception:
event.getLinkedException().addSuppressed(new RuntimeException(errorMessage));
and in the Endpoint I changed the RequestPayload the soapenvelope instead. The marshallingService wraps the jax2bmarshaller:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "ContactRequest")
#ResponsePayload
public ContactResponse handleContactRequest(#RequestPayload SoapEnvelope soapEnvelope) throws Exception {
ContactRequest contactRequest = marshallingService.unmarshalContact(soapEnvelope.getBody().getPayloadSource());
the marshallingService catch the exception, extract my suppressed exception message and throws that instead:
((UnmarshalException) xmlMappingException.getCause()).getLinkedException().getSuppressed()[0].getLocalizedMessage();
It is not an elegant solution but the endpoint produces much better error messages than before.
Have you tried using the PayloadValidatingInterceptor? That will validate the message before demarshalling as far as I know. Perhaps that'll give you some more insight in what is going wrong.
You can simply set it up in your application config:
private ClassPathResource yourXsdFile = new ClassPathResource("xsd.xsd");
#Bean
public PayloadValidatingInterceptor validatingInterceptor() {
PayloadValidatingInterceptor interceptor = new PayloadValidatingInterceptor();
interceptor.setSchema(yourXsdFile);
interceptor.setAddValidationErrorDetail(true);
return interceptor;
}
#Bean
public PayloadRootAnnotationMethodEndpointMapping endpointMapping() {
PayloadRootAnnotationMethodEndpointMapping mapping = new PayloadRootAnnotationMethodEndpointMapping();
mapping.setInterceptors(new EndpointInterceptor[]{
validatingInterceptor()
});
return mapping;
}
For more info check out the api docs.

Spring OXM 3 + JiBXException: No marshaller defined for class

I have used Spring OXM and JiBX in my application.
below is my Spring Config file
<context:component-scan base-package="com.controller"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<oxm:jibx-marshaller target-class="com.request.RequestClass" id="rqMarshaller"/>
<oxm:jibx-marshaller target-class="com.response.ResponseClass" id="rsMarshaller"/>
<bean id="xmlViewer" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg ref="rsMarshaller" />
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
below is controller class
#Controller
public class MyController {
#Autowired
private JibxMarshaller rqMarshaller;
#RequestMapping(value = "/myrequest", method = RequestMethod.POST)
public ModelAndView searchFlights(#RequestBody String request) {
System.out.println("Inside");
System.out.println("request = "+request);
Source source = new StreamSource(new StringReader(request));
RequestClass rq = null;
try {
rq = (RequestClass) rqMarshaller.unmarshal(source);
} catch (XmlMappingException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
ResponseClass e = new ResponseClass();
e.setVersion("2.0");
Orig ond = new Orig();
ond.setCode("AIT");
e.getOrig().add(ond);
return new ModelAndView("xmlViewer","object",e);
}
}
When i send XML request it marshaled successfully but for response i got following error message.
org.jibx.runtime.JiBXException: No marshaller defined for class com.response.ResponseClass
I have already defined marshaller for ResponseClassin spring config file.
please help. Thanks.
Finally i figured out the solution !!!
Need to specify the bindingName attribute while registering the JiBxMarshaller.
<oxm:jibx-marshaller target-class="com.request.RequestClass" id="rqMarshaller" bindingName="rqBinding"/>
<oxm:jibx-marshaller target-class="com.response.ResponseClass" id="rsMarshaller" bindingName="rsBinding/>
and specify same name in respective binding/mapping file of JiBX.
That's it !

Resources