Spring XStream Load Annotations and Fix MVC Issues

Wow. Covering the full gamut today. From Flex-Swiz-Event Order to Javascript-jQuery-Image Scaling to Java-Spring-Xml Marshalling.

The problem I faced was this (http://forum.springsource.org/showthread.php?t=79963). Essentially, Spring MVC / XStream sometimes maps a returned object (see below) to an incoherent string of framework object binding instructions.

The Spring MVC Service

 @Controller  
public class SessionService {
@Autowired
private ServerSessionContext serverSessionContext;
@RequestMapping(value = “/validatesession”)
public SessionValidationResponse validateSessionToken(@RequestParam String sessionToken) {
SessionValidationResponse response = new SessionValidationResponse();
response.isValid = serverSessionContext.doesSessionExist(sessionToken);
return response;
}
}

The actual returned object is nothing more than a simple POJO.

 package com.actifi.auth.dto;  
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias(“sessionValidationResponse”)
public class SessionValidationResponse {
public Boolean isValid = false;
}

But, it would return some Binding….

 <org.springframework.validation.BeanPropertyBindingResult>  
<nestedPath/>
<nestedPathStack serialization=“custom”>
<unserializable-parents/>
<vector>
<default>
<capacityIncrement>0</capacityIncrement>
<elementCount>0</elementCount>
thousands of lines omitted for brevity


The solution for fixing the problem is in the two reference links below. And… as they recommend… they want you to actually type class full names (package and all) into the spring config file. I like the way my current spring xml config looks…

  <!– oxm integration –>  
<bean id=“objectXmlMarshaller” class=“org.springframework.oxm.xstream.XStreamMarshaller”/>

So… here is a bootstrapper class and a scan class util to make things ‘automagic’.

Generic scan helper class (requires spring framework)

 package com.wookets.bootstrap;  
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.util.ClassUtils;
/**
* This will scan the classpath for certain classes that you may want to register based on annotations
* or something similar… This uses ASM and spring stuff, so we know it is good.
*
* usage
*
* final ComponentClassScanner scanner = new ComponentClassScanner();
* scanner.addIncludeFilter(new AnnotationTypeFilter(DbRevision.class));
* final List<Class<? extends Object>> classes = scanner.getComponentClasses(this.CLASS_PATH);
*
* @author wookets
*
*/
public class ComponentClassScanner extends ClassPathScanningCandidateComponentProvider {
public ComponentClassScanner() {
super(false);
}
public final List<Class<? extends Object>> getComponentClasses(String basePackage) {
basePackage = basePackage == null ? “” : basePackage;
final List<Class<? extends Object>> classes = new ArrayList<Class<? extends Object>>();
for(final BeanDefinition candidate : this.findCandidateComponents(basePackage)) {
try {
final Class<? extends Object> cls = ClassUtils.resolveClassName(candidate.getBeanClassName(), ClassUtils.getDefaultClassLoader());
classes.add(cls);
} catch (final Throwable ex) {
ex.printStackTrace();
}
}
return classes;
}
}

xstream xml bootstrapper. This will read in annotations and add classes to the supported classes property to avoid the above issues with binding bean things.

 package com.wookets.bootstrap;  
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.stereotype.Component;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* This will alias the xml types with the xml marsheller, so we can use annotations on our xml types and do all aliasing
* and caching up front.
*
* @author wookets
*
*/
@SuppressWarnings(“rawtypes”)
@Component
public class ServerStartupAliasXmlType implements ApplicationListener {
private boolean hasBeenCreated = false;
@Autowired
private XStreamMarshaller objectXmlMarshaller;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(this.hasBeenCreated)
return;
if(event instanceof ContextRefreshedEvent) {
this.hasBeenCreated = true;
final ComponentClassScanner scanner = new ComponentClassScanner();
scanner.addIncludeFilter(new AnnotationTypeFilter(XStreamAlias.class));
final List<Class<?>> classes = scanner.getComponentClasses(“com.wookets”);
for(final Class<?> c : classes) {
this.objectXmlMarshaller.getXStream().processAnnotations©;
}
this.objectXmlMarshaller.setSupportedClasses(classes.toArray(new Class[0]));
}
}
public void setObjectXmlMarshaller(XStreamMarshaller objectXmlMarshaller) {
this.objectXmlMarshaller = objectXmlMarshaller;
}
}

I think I had more to add, but… oh yeah… A link to some files to download…

http://wookets.com/code/java/SpringBootstrap/

References:

http://forum.springsource.org/showthread.php?t=97048

http://forum.springsource.org/showthread.php?t=79963

Published by using 506 words.