#XmlJavaTypeAdapter and wrappers - java

I don't want use XmlJavaTypeAdapter annotations with XmlAdapter's class in my code directly.
So, I wrote some wrapper:
class BinderWrapper<MODEL, BEAN> extends XmlAdapter<BEAN, MODEL>{
private final Binder<MODEL, BEAN> target;
private BinderWrapper(Binder<MODEL, BEAN> target){
this.target = target;
}
static <MODEL, BEAN> BinderWrapper<MODEL, BEAN> createInstance(Binder<MODEL, BEAN> binder){
return new BinderWrapper<MODEL, BEAN>(binder);
}
#Override
public MODEL unmarshal(BEAN v) throws Exception {
return target.unBean(v);
}
#Override
public BEAN marshal(MODEL v) throws Exception {
return target.toBean(v);
}
}
that's wrappes my binders like XmlAdapter s. All my binders will implements Binder interface
public interface Binder<MODEL, BEAN> {
MODEL unBean(BEAN bean);
BEAN toBean(MODEL model);
}
But there is a problem. #XmlJavaTypeAdapter require XmlAdapter class without any wrapper. How I can solve this problem? - use other annotation / write some config / write some magic annotation /..
Thanks.
upd
I have model classes that aren't JavaBeans. So I want do some two step mapping : in beans and than into xml. I want do first step with annotations too. Probably I well need this beans not only for JAXB. The real question is : can I do first step with some non JAXB annotations?

I have model classes that aren't
JavaBeans. So I want do some two step
mapping : in beans and than into xml.
I want do first step with annotations
too. Probably I well need this beans
not only for JAXB. The real question
is : can I do first step with some non
JAXB annotations?
The XmlAdapter provides the two step mapping you are looking for. If you look at the example linked below Map is the object that is not a Java Bean. What the XmlAdapter does is convert it to a Java Bean that can be mapped.
You may find it easier to use the #XmlJavaTypeAdapter annotation at the type level rather than the property level. When used at the type level you are saying everyone that references that class should use the adapter instead of per property. See my post on JAXB and Immutable Objects for a type level example.
For more information see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html

Related

Separate validation annotation and it's validator in separate modules

Situation: you have module with DTO objects used in your API, so that other project(s) can reuse then when sending requests. These DTO classes does have bean-validation annotations in them. And you would like to use your custom validations to validate DTO "arriving" via requests. The sender typically does not validate outgoing data, IIUC, and might not be interested in importing validators along with annotations.
Problem(?): bean-validation is defined in a way, where annotation defines who implements it (which is incorrect and it should be otherwise around imo), with possibility to specify empty array as annotation validator (seems like hack) and then pairing is done via manual hashmap manipulations instead of stuff like service loader etc.
How do you do this?
Would you split annotation and it's validator in separate modules?
How would you bind them together? I think it should be possible to use {} as validator and then use org.hibernate.validator.internal.metadata.core.ConstraintHelper#putValidatorDescriptors to bind them together, but I did not test it yet + maybe there is better way...
I agree that the annotation defining the validator does feel backwards. While not ideal, I've been able to work around this by separating my custom ConstraintValidator into an interface and implementation.
Example:
In api module define constraint and interface validator
#Constraint(validatedBy = MyConstraintValidator.class)
public #interface MyConstraint
{
}
public interface MyConstraintValidator
extends ConstraintValidator<MyConstraint, String>
{
}
In your service module define the implementation
public class MyConstraintValidatorImpl implements MyConstraintValidator
{
private FooService foo;
#Override
public boolean isValid( String value, ConstraintValidatorContext ctx)
{
// Implement your constraint logic
}
}
I we need to separate interface class and validator implementation into separate modules, it's possible. And even in a way, which I said in original question, that should be used. In API module you declare validation for example as:
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {})
#SupportedValidationTarget(ValidationTarget.ANNOTATED_ELEMENT)
#ReportAsSingleViolation
public #interface AnyUuid {
//...
notice validatedBy = {}. The validator implementation looks like:
public class AnyUuidValidator implements ConstraintValidator<AnyUuid, Object> {
//...
and pairing can be setup using service loader(see javadoc if you don't know how that works). Put into file META-INF/services/javax.validation.ConstraintValidator FQDN of AnyUuidValidator shown above. And all other custom validators. And that should be it.
There is a bug I found with this. If I'm not mistaken. If you have DTO you cannot change (~annotate with constraints) and still want to validate them via bean validation, you can register validation definitions via xml file. If you are doing so and use service loader for pairing definition and implementation of custom validators, there is probably some bug and your custom validators won't be found. So verify this scenario before relying on service loader. But maybe I'm wrong, for me it was feasible to drop this validation trivially so I did to save some time and could ignore this.

Using JAXB with JgraphX?

I have some entities mapped with JAXB annotations to turn them into xml, but within those entities mxCell there is an object, how can I map this object without adding annotations in the code library JgraphX​​?
There is my Objeto class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#XmlSeeAlso({mxCell.class})
public abstract class ObjetoImpl implements Serializable, Objeto {
#XmlAttribute
protected String nome;
#XmlAnyElement
protected mxCell cell;
#Override
public String toString() {
return this.nome;
}
}
It's give me the following exception:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.mxgraph.model.mxICell is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at com.mxgraph.model.mxICell
at public com.mxgraph.model.mxICell com.mxgraph.model.mxCell.getParent()
at com.mxgraph.model.mxCell
at #javax.xml.bind.annotation.XmlSeeAlso(value=[class com.mxgraph.model.mxCell])
at ardis.model.conceitual.atributo.Atributo
at protected java.util.List ardis.model.conceitual.ObjetoWithAttributeImpl.attributes
at ardis.model.conceitual.ObjetoWithAttributeImpl
at ardis.model.conceitual.entidade.Entidade
at #javax.xml.bind.annotation.XmlSeeAlso(value=[class ardis.model.conceitual.entidade.Entidade])
at ardis.model.conceitual.ModeloConceitual
That exception occurs when the implementation of the interface is not correctly mapped with Jaxb, but i don't want enter into the jgraphx library and modify it
There are a couple of ways that you can handle this use case:
Option #1 - Specify the Impl Class with #XmlElement
For fields/properties that are of an interface type can use the #XmlElement annotation to specify the concrete implementation.
#XmlElemen(type=mxCellImpl.class)
protected mxCell cell;
For More Information
http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html
Option #2 - Use an XmlAdapter
An XmlAdapter allows you to convert an unmappable object to a mappable one during the marshalling/unmarshalling process. You could use this to convert JgraphX into your own domain object.
For More Information
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
I could not convert the objects of the program who had a mxCell inside using JAXB, so the solution for me was use the JgraphX "getXml" to convert the graph elements and the values of each cell. After that I get the value of the cells and use at my code.
The code to pass the graph to xml:
mxCodec codec = new mxCodec();
String xml = mxXmlUtils.getXml(codec.encode(graph.getModel()));

What's the common way to deal with Jackson serialization

Currently I have a project that makes use of Spring-Hibernate and also Jackson to deal with JSON. The first time I tried to use Jackson I always got LazyInitializationException and sometimes infinite loop for multiple entities that references each other. Then I found #JsonIgnore and #JsonIdentityInfo.
Now the problem is sometimes it is needed to ignore properties but sometimes I just need those properties to be serializable. Is there a way to sometimes ignore several fields and sometimes serialize the fields at the runtime?
I found "Serialization and Deserialization with Jackson: how to programmatically ignore fields?"
But if I always have to use the mix in annotation, it would be cumbersome if an object dozens of properties to retrieve. Eg. In page1 I need propertyA, propertyB, propertyC; in page2 I need propertyA and propertyC; in page3 I only need propertyB. In those cases alone I would have to create 1 class for each page resulting in 3 classes.
So in that case is there a way to define something like:
objectA.ignoreAllExcept('propertyA');
String[] properties = {'propertyA', 'propertyC'};
objectB.ignoreAllExcept(properties); // Retrieve propertyA and propertyC
objectC.ignore(properties);
What you might be looking for is a Module. The documentation says that Modules are
Simple interface for extensions that can be registered with ObjectMappers to provide a well-defined set of extensions to default functionality.
Following is am example of how you might use them to accomplish what you want. Note, there are other ways using which this can be achieved; this is just one of them.
A simple DTO that can be used for specifying the properties to filter:
public class PropertyFilter {
public Class<?> classToFilter;
public Set<String> propertiesToIgnore = Collections.emptySet();
public PropertyFilter(Class<?> classToFilter, Set<String> propertiesToIgnore) {
this.classToFilter = classToFilter;
this.propertiesToIgnore = propertiesToIgnore;
}
}
A custom module that filters out properties based on some attribute that you store in the current request.
public class MyModule extends Module {
#Override
public String getModuleName() {
return "Test Module";
}
#Override
public void setupModule(SetupContext context) {
context.addBeanSerializerModifier(new MySerializerModifier());
}
#Override
public Version version() {
// Modify if you need to.
return Version.unknownVersion();
}
public static class MySerializerModifier extends BeanSerializerModifier {
public BeanSerializerBuilder updateBuilder(SerializationConfig config,
BeanDescription beanDesc,
BeanSerializerBuilder builder) {
List<PropertyFilter> filters = (List<PropertyFilter>) RequestContextHolder.getRequestAttributes().getAttribute("filters", RequestAttributes.SCOPE_REQUEST);
PropertyFilter filter = getPropertyFilterForClass(filters, beanDesc.getBeanClass());
if(filter == null) {
return builder;
}
List<BeanPropertyWriter> propsToWrite = new ArrayList<BeanPropertyWriter>();
for(BeanPropertyWriter writer : builder.getProperties()) {
if(!filter.propertiesToIgnore.contains(writer.getName())) {
propsToWrite.add(writer);
}
}
builder.setProperties(propsToWrite);
return builder;
}
private PropertyFilter getPropertyFilterForClass(List<PropertyFilter> filters, Class<?> classToCheck) {
for(PropertyFilter f : filters) {
if(f.classToFilter.equals(classToCheck)) {
return f;
}
}
return null;
}
}
}
Note: There is a changeProperties method in the BeanSerializerModifier class that is more appropriate for changing the property list (according to the documentation). So you can move the code written in the updateBuilder to changeProperties method with appropriate changes.
Now, you need to register this custom module with your ObjectMapper. You can get the Jackson HTTP message converter from your application context, and get its object mapper. I am assuming you already know how to do that as you have been dealing with the lazy-initialization issue as well.
// Figure out a way to get the ObjectMapper.
MappingJackson2HttpMessageConverter converter = ... // get the jackson-mapper;
converter.getObjectMapper().registerModule(new MyModule())
And you are done. When you want to customize the serialization for a particular type of object, create a PropertyFilter for that, put it in a List and make it available as an attribute in the current request. This is just a simple example. You might need to tweak it a bit to suit your needs.
In your question, you seem to be looking for a way to specify the properties-to-filter-out on the serialized objects themselves. That, in my opinion, should be avoided as the list of properties to filter-out doesn't belong to your entities. However, if you do want to do that, create an interface that provides setters and getters for the list of properties. Suppose the name of the interface is CustomSerialized Then, you can modify the MyModule class to look for the instances of this CustomSerialized interface and filter out the properties accordingly.
Note: You might need to adjust/tweak a few things based on the versions of the libraries you are using.
I think there is a more flexible way to do it. You can configure Jackson in a such a way that it will silently ignore lazy loaded properties instead of stopping serialization process. So you can reuse the same class. Just load all necessary properties / relations and pass it to Jackson. You can try to do it by declaring your custom ObjectMapper and by turning off SerializationFeature.FAIL_ON_EMPTY_BEANS feature. Hope it helps.
You can filter out properties without modifying classes by creating a static interface for a mixin annotation. Next, annotate that interface with the #JsonFilter annotation. Create a SimpleBeanPropertyFilter and a SimpleFilterProvider. Then create an ObjectWriter with your filter provider by invoking objectMapper.writer(filterProvider)

How can I tell jackson to ignore a property for which I don't have control over the source code?

Long story short, one of my entities has a GeometryCollection that throws an exception when you call "getBoundary" (the why of this is another book, for now let's say this is the way it works).
Is there a way I can tell Jackson not to include that specific getter? I know I can use #JacksonIgnore when I do own/control the code. But this is not case, jackson ends reaching this point through continuous serialization of the parent objects. I saw a filtering option in jackson documentation. Is that a plausible solution?
Thanks!
You can use Jackson Mixins. For example:
class YourClass {
public int ignoreThis() { return 0; }
}
With this Mixin
abstract class MixIn {
#JsonIgnore abstract int ignoreThis(); // we don't need it!
}
With this:
objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);
Edit:
Thanks to the comments, with Jackson 2.5+, the API has changed and should be called with objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)
One other possibility is, if you want to ignore all unknown properties, you can configure the mapper as follows:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Using Java Class
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
Using Annotation
#JsonIgnoreProperties(ignoreUnknown=true)
Annotation based approach is better. But sometimes manual operation is needed. For this purpose you can use without method of ObjectWriter.
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String jsonText = writer.writeValueAsString(sourceObject);
Mix-in annotations work pretty well here as already mentioned. Another possibility beyond per-property #JsonIgnore is to use #JsonIgnoreType if you have a type that should never be included (i.e. if all instances of GeometryCollection properties should be ignored). You can then either add it directly (if you control the type), or using mix-in, like:
#JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule
This can be more convenient if you have lots of classes that all have a single 'IgnoredType getContext()' accessor or so (which is the case for many frameworks)
I had a similar issue, but it was related to Hibernate's bi-directional relationships. I wanted to show one side of the relationship and programmatically ignore the other, depending on what view I was dealing with. If you can't do that, you end up with nasty StackOverflowExceptions. For instance, if I had these objects
public class A{
Long id;
String name;
List<B> children;
}
public class B{
Long id;
A parent;
}
I would want to programmatically ignore the parent field in B if I were looking at A, and ignore the children field in A if I were looking at B.
I started off using mixins to do this, but that very quickly becomes horrible; you have so many useless classes laying around that exist solely to format data. I ended up writing my own serializer to handle this in a cleaner way: https://github.com/monitorjbl/json-view.
It allows you programmatically specify what fields to ignore:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);
List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
.onClass(B.class, match()
.exclude("parent")));
It also lets you easily specify very simplified views through wildcard matchers:
String json = mapper.writeValueAsString(JsonView.with(list)
.onClass(A.class, match()
.exclude("*")
.include("id", "name")));
In my original case, the need for simple views like this was to show the bare minimum about the parent/child, but it also became useful for our role-based security. Less privileged views of objects needed to return less information about the object.
All of this comes from the serializer, but I was using Spring MVC in my app. To get it to properly handle these cases, I wrote an integration that you can drop in to existing Spring controller classes:
#Controller
public class JsonController {
private JsonResult json = JsonResult.instance();
#Autowired
private TestObjectService service;
#RequestMapping(method = RequestMethod.GET, value = "/bean")
#ResponseBody
public List<TestObject> getTestObject() {
List<TestObject> list = service.list();
return json.use(JsonView.with(list)
.onClass(TestObject.class, Match.match()
.exclude("int1")
.include("ignoredDirect")))
.returnValue();
}
}
Both are available on Maven Central. I hope it helps someone else out there, this is a particularly ugly problem with Jackson that didn't have a good solution for my case.
If you want to ALWAYS exclude certain properties for any class, you could use setMixInResolver method:
#JsonIgnoreProperties({"id", "index", "version"})
abstract class MixIn {
}
mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
#Override
public Class<?> findMixInClassFor(Class<?> cls) {
return MixIn.class;
}
#Override
public ClassIntrospector.MixInResolver copy() {
return this;
}
});
One more good point here is to use #JsonFilter.
Some details here Feature: JSON Filter

How-to dynamically fill a annotation

Sadly, I forgot to take the code from work with me today. But maybe this little example will clarify things.
I use hibernate to map a bean to a table.
Example:
import javax.persistence.column;
….
String columnameA;
….
#Column(name="columnameA")
public String getColumname(){
return columnameA
}
….
I do not want to hardcode the columnname (“columnameA”) in my sourcecode, because I need to switch the columname without building the entire project.
I wanted to use something like:
#Column(name=getColumnName())
This does not work. The idea is, to to write the columnname somewhere in the jndi tree and use it at startup. So i only need to restart the application to change the columnname.
The only way around this problem – which I can think of – is to write my own annotation, which extends the hibernate class. Is there a simpler way of doing this?
You can't achieve this with annotations, but a solution to your specific problem is to implement a custom NamingStrategy:
public class NamingStrategyWrapper implements NamingStrategy {
private NamingStrategy target;
public NamingStrategyWrapper(NamingStrategy target) {
this.target = target;
}
public String columnName(String arg0) {
if ("columnameA".equals(arg0)) return getColumnName();
else return target.columnName(arg0);
}
...
}
-
AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.setNamingStrategy(new NamingStrategyWrapper(cfg.getNamingStrategy()));
factory = cfg.configure().buildSessionFactory();
The only values you can assign to attributes are constant values, specified by hand, or stored in public static final variables.
Annotations do not define behavior, but only meta-informations about class, methods and the likes. You can specify behavior in annotation processors, that read your annotations and generate new source code or other files.
Writing an annotation processo is beyond my knowledge, but you could find other information in the Annotations Processing Tool guide by Sun.

Categories