Marshalling polymorphic objects in JAX-WS - java

I'm creating a JAX-WS type webservice, with operations that return an object WebServiceReply. The class WebServiceReply itself contains a field of type Object. The individual operations would populate that field with a few different data-types, depending on the operation.
Publishing the WSDL (I'm using Netbeans 6.7), and getting a ASP.NET application to retrieve and parse the WSDL was fine, but when I tried to call an operation, I would receive the following exception:
javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: class [LDataObject.Patient; nor any of its super class is known to this context.]
How do I mark the annotations in the DataObject.Patient class, as well as the WebServiceReply class to get it to work? I haven't been able to fine a definitive resource on marshalling based upon annotations within the target classes either, so it would be great if anybody could point me to that too.
WebServiceReply.java
#XmlRootElement(name="WebServiceReply")
public class WebServiceReply {
private Object returnedObject;
private String returnedType;
private String message;
private String errorMessage;
.......... // Getters and setters follow
}
DataObject.Patient.java
#XmlRootElement(name="Patient")
public class Patient {
private int uid;
private Date versionDateTime;
private String name;
private String identityNumber;
private List<Address> addressList;
private List<ContactNumber> contactNumberList;
private List<Appointment> appointmentList;
private List<Case> caseList;
}
Solution
(Thanks to Gregory Mostizky for his answer)
I edited the WebServiceReply class so that all the possible return objects extend from a new class ReturnValueBase, and added the annotations using #XmlSeeAlso to ReturnValueBase. JAXB worked properly after that!
Nonetheless, I'm still learning about JAXB marshalling in JAX-WS, so it would be great if anyone can still post any tutorial on this.
Gregory: you might want to add-on to your answer that the return objects need to sub-class from ReturnValueBase. Thanks a lot for your help! I had been going bonkers over this problem for so long!

You need to use #XmlSeeAlso so that your JAXB implementation will now to include additional classes as well.
In your case it would go something like this:
#XmlRootElement
#XmlSeeAlso({Patient.class, ....})
public class ReturnValueBase {
}
And also change returnedObject property to be of type ReturnValueBase.

Related

Get domain type for custom repository in Spring

Good afternoon, This is my first question here on StackOverflow.
I'm not an expert with the Spring framework and sometimes i get lost for a lot of time for problems that are relatively easy to solve, but this time i can't really get out of it.
I'm trying to implement a method inside a custom Spring Data Repository that should work with multiple Entities and perform some operations on the database, based on the presence of particular annotations on Entity's fields.
I've tried a lot of workarounds found on the internet but i'm not actually able to achieve the result i need. I'll try to be more specific:
This is an example Entity with the annotations:
#Data
#Entity
#MyAnnotation
public class User{
#Id
#MyDataAnnotation
private Long id;
#MyDataAnnotation
private String firstName;
#MyDataAnnotation
private String lastName;
private String userName;
private int followers;
private int following;
}
I have then inside the UserService class something like this:
#Service
public class UserService {
private final UserRepository repository;
public void doSomethingOnUser(Long id){
repository.myCustomMethod(id);
}
}
For the UserRepository i did something like this, just very basic stuffs:
#Repository
public interface UserRepository extends CrudRepository<User,Long>,MyCustomRepository<User,Long> {}
The i have the custom repo interface:
public interface MyCustomRepository<T,ID>{
public void myCustomMethod(ID id);
}
And finally the implementation of myCustomMethod:
public class MyCustomRepositoryImpl <T,ID> implements MyCustomRepository{
#PersistenceContext
EntityManager entityManager;
#Override
public void myCustomMethod(Object id){
User user = entityManager.find(User.class,id);
List<Field> markedFields = MyAnnotationProcessor.getAnnotated(user.getClass());
//Here I'll manipulate the fields that i've obtained
...
entityManager.persist(u);
//And then i'm persisting the modified entity
}
}
This is actually working with the User Entity, but i need to find a way to have it working for every domain type managed by a repository that extends MyCustomRepository.
For example if i have:
public interface WhateverRepository extends CrudRepository<WhateverClass,Long>,MyCustomRepository<WhatheverClass,Long>
myCustomMethod should do his stuffs anyway.
One thing i tried was to retrieve a Class<T> instance with this piece of code:
private final Class<T> type;
public MyCustomRepositoryImpl(Class<T> type) {
this.type = type;
}
And using type instead of User.class but it fails to load the ApplicationContext:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.Class<?>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}`
Thanks if you've read till here, hope you can give me some hints and if I wasn't clear enough please don't hesitate to ask me for further informations.
Update:
Following #amineT answer i tried to use the GenericTypeResolver provided by Spring, but instead of the types i actually get null.
The documentation states that if null is returned, it means that it wasn't able to resolve the type.
This is the code i used:
private final Class<?>[] genericType;
public MyCustomRepositoryImpl(){
this.genericType = GenericTypeResolver.resolveTypeArguments(getClass(), MyCustomRepositoryImpl.class);
}
I think that somehow this "problem" is related to all the proxying that Spring is doing under the hood, but i don't have any precise idea at the moment.
If someone has any clues please write it down here, it'll be appreciated.
I had a similar problem and this answer helped me out. You're geting the NoSuchBeanDefinitionException because you're trying to inject a class type field but you didn't create one in Spring context. What you need to do is use Spring's GenericTypeResolver to find the generic type and process your data accordingly.
Hope this helps
Actually, referencing from the answer pointed by #amineT, I've created a sample project to see if it suits your problem.
From my understanding, what you want should be to determine the type of the bean at runtime not the type of CustomRepositoryImpl. After I built my sample project, I find that your code is almost correct.
Here is a sample of what I would do to your code to make it work:
#Override
public void myCustomMethod(Class cls, Object id){
Object user = entityManager.find(cls,id);
List<Field> markedFields = MyAnnotationProcessor.getAnnotated(cls);
//Here I'll manipulate the fields that i've obtained
...
entityManager.persist(u);
//And then i'm persisting the modified entity
}
Also, here is my github for the sample project I've created.

Is there a way that I donot need add #JsonProperties for boolean field when mapping json to pojo using jackson&spring mvc

I cannot find a way to fix this issue, but... maybe it's not an issue.
I use Extjs as the front-end and Spring MVC as backend, the Ajax request looks like:
{"isOk": true}
The Mapping DTO is:
public class TestDTO implements Serializable {
private static final long serialVersionUID = -6074462313103219627L;
private Boolean isOK;
public Boolean isOk(){...}
Public void setOk(Boolean isOk){...}
}
The get/set method be generated by intellij idea, as you can imagine that jackson works fine if I add #JsonProperty("isOk") under the "setOk" method.
But I have a lot of ***DTO objects, so is there a convenient method to reslove this issue? thanks.
I have checked the "com.fasterxml.jackson.databind.SerializationFeature" class, and didn't find any config which like the "compatible_boolean_and_ignore_is_keyword" etc..
I didn't test it, but might be helpful for your case:
https://stackoverflow.com/a/35088196/677937
Basically, try to rename your getter/setter to:
getIsOk / setIsOk
It should then serialize/deserialize json in form of {"isOk": ... }
It's been some time since I used spring, but if I recall correctly you have to
annotate the class with #Entity
implement the Serializable interface (class DTO implements Serializable)
provide a default constructor

#JsonView: different perspectives

I'm coding a Spring Web Service, using Jackson by default. I'm using #JsonView to indicate which property I need to be parsed to my JSON object. So, the problem is: Many objects are used in different classes, but not exactly all its properties, for example:
class Professor {
#JsonView({Views.Public.class, Views.Internal.class})
private int id;
#JsonView(Views.Internal.class)
private String name;
...
}
class Classroom {
#JsonView({Views.Public.class, Views.Internal.class})
private int id;
#JsonView(Views.Internal.class)
private String name;
...
}
class Lecture {
#JsonView(Views.Public.class)
private Professor professor;
#JsonView(Views.Public.class)
private Classroom classroom;
...
}
What if I need more than two 'perspectives', I'd have to create more interfaces/classes to do that? (like Views.Professor, Views.Principal, ...) Is this a real good practice?
I'd like to hear some suggestions or alternatives to solve that. I'm a little bit confused about being on the right track.
Generic names
You always can define more views if you need more perspectives, that's the idea behind the Jackson JSON views and that's what makes it flexible.
If you use generic names in your views classes, such as Basic, Extended, Public, Private and so on, you'll find it easier to reuse them across multiple beans.
Inheritance
You always can rely on inheritance with #JsonView. Consider the following example where Views.Private extends Views.Public:
public class Views {
interface Public {}
interface Private extends Public {}
}
Serialization of properties annotated with #JsonView(Views.Private.class) will also include properties annotated with #JsonView(Views.Public.class).

What is the purpose of using #PortableProperty

I recently came across a part of code which has annotation #PortableProperty used for variables declared in a DTO. Can anyone please explain what it does and the need for using it?
Portable marks a class as being eligible for use by a PofAnnotationSerializer. This annotation is only permitted at the class level and is a marker annotation with no members. The following class illustrates how to use Portable and PortableProperty annotations.
A PortableProperty marks a member variable or method accessor as a POF serialized attribute. Whilst the value() and codec() can be explicitly specified they can be determined by classes that use this annotation. Hence these attributes serve as hints to the underlying parser.
Quoted this from doc found here and here. Check this for more details.
Example:
public class Book
extends ExternalIdEntity
implements Serializable, PortableObject {
#PortableProperty(1)
private String id;
#PortableProperty(3)
private String parentId;
#PortableProperty(4)
private String name;
#PortableProperty(5)
private String legalEntityId;
...
}

JAXB and different versions of the class

I wonder if there is any support for different versions of class in JAXB.
My thoughts about it: xml is kind of persistence object of class (serialized value) but class object can be changed due to development (e.g. extending the functionality). Is there any way to know which version of class is stored in persistence (read: xml) using only JAXB API?
For me it seems convenient to store class version - like it's done in standard java serialization mechanism (I mean serialVersionUID) and provide functionality to map xml on class even in case of different version (e.g. adding in XmlAdapter information about version of class stored in xml). By default, if version of class in xml and in runtime differs - throw InvalidClassException.
Example:
We have class Test as follows:
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private Long time;
private Test () {};
}
assuming that time is UNIX time in millis.
This code was released on production and this class was persisted in the database as xml.
Next release shows that it was not good choice to use Long as time representation and it was changed to Date:
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private Date time;
private Test () {};
}
Now there are two ways - either to migrate persisted data or to write xml adapter which will handle Long time and apply it to the Date time.
If we choose the second way it would be great if JAXB API provides class version which were stored in xml (assuming if no class version is specified in class = 0 version) and we add new version of class explicitly (either by annotation or by static field):
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
#XmlClassVersion(value = 1)
public class Test {
private Date time;
private Test () {};
}
or
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
public class Test {
private static final long xmlSerialVersionUID = 1;
private Date time;
private Test () {};
}
and JAXB will provide XmlAdapter as follows:
public abstract class XmlAdapter<ValueType,BoundType> {
protected XmlAdapter() {}
public abstract BoundType unmarshal(ValueType v, long classVersion) throws Exception;
public abstract ValueType marshal(BoundType v, long classVersion) throws Exception;
}
In order to support multiple versions, of course, we need to implement such adapter and handle different versions explicitly.
Clearly, then, JAXB will add special information about class in xml and will generate xml on the latest class version.
NOTE: the point of the example above that we have 2 different representations of class in the persistence simultaneously but still can map them to the version of class available in the runtime.
JAXB stands for "Java Architecture for XML Binding", so, it's about binding objects fields values to XML elements/attributes, and not about serializing java objects. In you read for example this article, you see that it says
javax.xml.bind, contains classes and interfaces for performing
operations such as unmarshalling, marshalling, and validation
Java object serialization is another thing, and it's related to the serialVersionUID that you mention in your question.
If you are using JAXB you would be persisting xml and not the java object. If you were persisting java object it would be serialization. Jaxb transformation tries to bind the xml values to the class attributes. As long as the transformation prerequisites work, there shouldn't be a problem. Other libraries like JIBX, try to access bytecode directly. The class version may be an issue in such a case.

Categories

Resources