Why is XStream ignoring #XmlTransient? - jaxb

Does XStream handle JAXB #XmlTransient attributes by default? XStream seems to be ignoring the #XmlTransient attribute & serializing the field anyway.
In the sample code below. ExampleClass2 is getting serialized even though I don't want it to be. Further details are that these classes are being populated by OpenJPA.
XStream Code
XStream _x0 =null;
_x = XStreamImpl.getInstance();
_x.toXML(_object)
Class I want to serialize
#DataCache
#Entity
public class ExampleClass implements Serializable {
private short defaultOption;
private int primaryKey;
private short orderId;
#XmlTransient
private ExampleClass2 _exampleClass2;
#XmlTransient
public ExampleClass2 getTblPpwsCommCfgCombo() {
return _exampleClass2;
}
#XmlTransient
public void setExampleClass2(ExampleClass2 _exampleClass2) {
this._exampleClass2 = _exampleClass2;
}
public short getDefaultOption() {
return defaultOption;
}
public void setDefaultOption(short defaultOption) {
this.defaultOption = defaultOption;
}
public short getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(int primaryKey) {
this.primaryKey = primaryKey;
}
public short getOrderId() {
return orderId;
}
public void setOrderId(short orderId) {
this.orderId = orderId;
}
}

You can use the #Transient annotation or transiet key word:
#Transient
private ExampleClass2 _exampleClass2;
~

Related

Model mapper mapping Map<String,Object> to class which extends another generic class not working for list field

I am trying to create my custom configuration object from Map using model mapper. Everything gets mapped properly excepts the fields property which is coming fro Generic super class.
My target object is
public class ADParserConfig extends CustomParserConfig<ADParserConfigField> {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
This extends generic class CustomParserConfig
public class CustomParserConfig<T extends CustomParserConfigField> {
protected List<T> fields;
protected String timeStampField;
public List<T> getFields() {
return fields;
}
public void setFields(List<T> fields) {
this.fields = fields;
}
public String getTimeStampField() {
return timeStampField;
}
public void setTimeStampField(String timeStampField) {
this.timeStampField = timeStampField;
}
}
Where CustomParserConfigField is
public class CustomParserConfigField {
protected String name;
protected Integer index;
protected String type;
protected String format;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
I am trying to map Map using below function
ADParserConfig adParserConfig = getConfig(map,ADParserConfig.class);
public <T extends CustomParserConfig> T getConfig(Map<String,Object> configObject, Class<T> classType){
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(configObject,classType);
}
Everything excepts fields gets mapped properly for the below map.
{fields=[{name=timeStamp, type=timestamp, format=dd/mm/yyyy HH:MM:SS a}, {name=logName, type=string}], pattern=(?<timeStamp>\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}:\d{2}\s[AMPMampm]{2})?\s(LogName=(?<logName>[\w\s\W]+))?\sSourceName=(?<sourceName>[\w\s\W]+)\sEventCode=(?<eventCode>[0-9]*), timeStampField=timestamp}
Please help. Why is issue happens only for fields object ? Do I need to specify something else in mapper configurations ?
It looks like a bug and it had been fixed by #370

JaxB Marshaling in camel

I am new to Apache camel and Jax b concept in java.
I have a list of java objects in a camel queue. I want to Marshall it to an xml with Javs DSL(without using spring).
Could any one guide me to do that?
I have the following POJO class
public class MyPojo {
private int groupId;
private int memberId;
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}
following is my camel code for jaxb implementation
JaxbDataFormat jaxbMarshal = new JaxbDataFormat();
jaxbMarshal.setContextPath("com.test");
jaxbMarshal.setPartClass("com.test.MyPojo");
from("direct:javaObjects") //this direct having the list of MYPojo Objects
.marshal(jaxbMarshal)
.to("src/output");
I am getting below exception(I added maven dependency for jaxb in classpath)
Failed to create route route4 at: >>> Marshal[org.apache.camel.model.dataformat.JaxbDataFormat#3feb2dda] <<< in route: Route(route4)[[From[direct:javaObjects]] -> [Marshal[org.apa... because of Data format 'jaxb' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
I have created the jaxb.index file(new->File from eclipse). the content of the file should be annotation class name
In our case it should be
MyPojo
and its needs to be placed in context path. in our case it should be placed in
com.test location
and the annotated Pojo class is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class MyPojo {
#XmlElement
private int groupId;
#XmlElement
private int memberId;
#XmlElement
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}
You can use your pojo with some annotations:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="MY-POJO")
#XmlType(propOrder = {"groupId", "memberId", "details"})
public class MyPojo {
#XmlElement(name = "groupId")
private int groupId;
#XmlElement(name = "memberId")
private int memberId;
#XmlElement(name = "details")
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}

#CacheEvict with key="#id" throws NullPointerException

I'm trying to use Spring Caching annotations #Cacheable and #CacheEvict together with the GuavaCacheManager.
I've created a test case with these two tests:
cachesById - verifies that two invocations to a method annotatted with #Cacheable returns the same object
evict - verifies that two different instances are returned if a method annotated with #CacheEvict is called in-between those two invocations
Both work fine when i don't specify a key for #CacheEvict, however when I do i get the following exception:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:210)
at com.google.common.cache.LocalCache$LocalManualCache.invalidate(LocalCache.java:4764)
at org.springframework.cache.guava.GuavaCache.evict(GuavaCache.java:135)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doEvict(AbstractCacheInvoker.java:95)
at org.springframework.cache.interceptor.CacheAspectSupport.performCacheEvict(CacheAspectSupport.java:409)
at org.springframework.cache.interceptor.CacheAspectSupport.processCacheEvicts(CacheAspectSupport.java:392)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:362)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.myorg.caching.CacheTest$Repo$$EnhancerBySpringCGLIB$$eed50f3e.update(<generated>)
at com.myorg.caching.CacheTest.evict(CacheTest.java:50)
This can be reproduced by executing the below test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = { Repo.class, CacheTest.SpringConfig.class },
loader = AnnotationConfigContextLoader.class)
public class CacheTest {
private static final String CACHE_NAME = "cacheName";
#Inject
private Repo repo;
#Test
public void cachesById() {
Entity aResult1 = repo.getEntity(1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertSame(aResult1, aResult2);
}
#Test
public void evict() {
Entity aResult1 = repo.getEntity(1);
repo.update(aResult1);
Entity aResult2 = repo.getEntity(1);
assertEquals(aResult1.getId(), aResult2.getId());
assertNotSame(aResult1, aResult2);
}
/** Mock repository/entity classes below. */
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
public static class Entity {
private int id;
public Entity(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
/** Guava Cachemanager Spring configuration */
#Configuration
#EnableCaching
public static class SpringConfig {
#Bean
public CacheManager cacheManager() {
GuavaCacheManager manager = new GuavaCacheManager(CACHE_NAME);
manager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(
1, TimeUnit.MINUTES).recordStats());
return manager;
}
}
}
However the test passes if I change
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
into:
#CacheEvict(value = CACHE_NAME)
public void update(Entity e) {
..but then I'm missing the point where I need to specify the cache key for Entity. Does anyone know what I'm missing?
Thanks!
You have to fix you component class from
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#id")
public void update(Entity e) {
}
}
to
#Component
public static class Repo {
#Cacheable(value = CACHE_NAME, key = "#id")
public Entity getEntity(int id) {
return new Entity(id);
}
#CacheEvict(value = CACHE_NAME, key = "#e?.id")
public void update(Entity e) {
}
}
Why? In getEntity method you're caching an Entity object using int id, you have to pass the same int id into the #CacheEvict annotated method. You don't have to change method's signature - by using SPEL you can "get into" entity and use its id field.
Hope I helped.

JAXB: using #XmlID along with Hibernate #Id

I have following hibernate property:
#Id()
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id = null;
I want to add JAXB annotation #XmlID to this id but #XmlID can only be applied to String data types. How can I solve this problem.
#XmlID
#Transient
public String getXId(){
return this.id;
}
public String setXId(String s){
this.id = Long.parseDouble(s);
}
Use #XmlJavaTypeAdapter(IDAdapter.class) along with #XmlID where IDAdapter is
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class IDAdapter extends XmlAdapter<String, Long> {
#Override
public Long unmarshal(String string) throws Exception {
return DatatypeConverter.parseLong(string);
}
#Override
public String marshal(Long value) throws Exception {
return DatatypeConverter.printLong(value);
}
}

Marshall object field as attribute

Here is what I have so far to marshall my POJO using JAXB :
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlElement
public Entity getEntity() {
return entity;
}
}
and
#XmlRootElement
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute
public String getName(){
return this.name;
}
public void setComment...
#XmlAttribute
public void getComment...
}
With that, I get something like this:
<local>
<entity name="" comment=""></entity>
</local>
However, I would prefer to have the name attribute as an attribute of the local:
<local entityName="" entityComment=""></local>
Is the XmlJavaTypeAdapter a good way to begin with?
Thanks,
Alex
There are a couple of different options to handle this use case:
Option #1 - XmlAdapter (Any JAXB implementation)
You could use an XmlAdapter for this use case. This will work as long as only one attribute value comes from the Entity object:
EntityAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class EntityAdapter extends XmlAdapter<String, Entity>{
#Override
public String marshal(Entity entity) throws Exception {
if(null == entity) {
return null;
}
return entity.getName();
}
#Override
public Entity unmarshal(String name) throws Exception {
Entity entity = new Entity();
entity.setName(name);
return entity;
}
}
Local
The XmlAdapter is linked with the field/property using the #XmlJavaTypeAdapter annotation:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlAttribute
#XmlJavaTypeAdapter(EntityAdapter.class)
public Entity getEntity() {
return entity;
}
}
For More Information
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html
Option #2 - #XmlPath (EclipseLink JAXB (MOXy)
Alternatively if you are using EclipseLink JAXB (MOXy), the you could use the #XmlPath extension. This is useful with the Entity object corresponds to multiple XML attributes:
Local
Specifying the XPath "." indicated that the child contents will be written into the parent element
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlPath(".")
public Entity getEntity() {
return entity;
}
}
Entity
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute(name="entityName")
public String getName(){
return this.name;
}
public void setComment(String comment){
this.comment = comment;
}
#XmlAttribute(name="entityComment")
public String getComment(){
return this.comment;
}
}
For More Information
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Resources