Jersey Jaxb Issues - rest

We are having a problem with generic Payload while using Jersey. Here is our Domain object.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Event<T> {
private T eventPayload;
private String eventType;
}
Here we have top level domain object defined. But the internal domain object is generic.
Now on the resource endpoint we have something like this as we know that the sub-domain object we were expecting is.
#POST
#Path("log")
#Consumes(MediaType.APPLICATION_XML)
public Response writeLog(Event<LogPayload> event)
But this doesn’t work.
The event instance is created but the subdomain is not populated correctly.
It just tries to populate the sub-domain object with any random domain object which has the same root element as in the XML (there may be more than one).
Our Solution:
This is our solution, but I am sure this is not the best.
We have to modify our parent domain object have a String variable which stores XML-representation of the generic payload in a String format. For this we have had to write our own Jaxb marshaller.
Modifications to the Event
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Event<T> {
#XmlTransient
private T eventPayload;
private String eventType;
private String payLoadXML;
// Changes to the constructor:
public Event(T eventPayload ……) {
super();
this.eventPayload = eventPayload;
payLoadXML = JAXBUtils.marshall(eventPayload,false); }}
On the resource side once we get the parent Event object, we have to again use our own jaxb marshaller to get the required domain object from the payloadXML as follows.
#POST
#Path("log")
#Consumes(MediaType.APPLICATION_XML)
public Response writeLog(Event<LogPayload> event)
LogPayload log1 = (LogPayload) JAXBUtils.unMarshall(
event.getPayLoadXML(),LogPayload.class);
So ineffect we are using our jaxbmarshaller to marshall and unmarshall the generic subdomain object before and after making the rest call….
Please lets us know if there is a better way to do this ?
Thanks,
ND

I've seen the same question before and I don't think this will work as you originally planned. Web services (json/xml, rest/soap) usually create a service description (like wsdl) and a generic type technically cannot be part of this description. What you could do is to publish multiple services where Event is not generic anymore.

Related

What is the professional/standard way to save an object with a foreign key?

I am developing a simple dictionary RESTful API with Spring-mvc. There are two related entities:
public class Word {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String word;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="LANGUAGE_ID", insertable=false, updatable=false)
private Language language;
}
Based on the code above the related entity is Language.
Issue: I would like to implement the CREATE operation on the Word entity with POST request. The implementation is not difficult, but I did find at least two solution candidates in relation to the POST request URL and JSON request body:
Solution Candicate I: directly insert with JSON body request. The JSON body contain the nested JSON object - Language, something like
{id:1, word:"hello", Language: {id:1, language:"English"}}
reference: Spring: Save object with foreign keys with a POST request
Solution Candidate II: get the referenced Language id through the POST request URL, say something like
POST http://localhost:8080/rest/language/1/words
As such, there is no Language reference at all in the JSON POST request body.
reference: https://www.youtube.com/watch?v=_Jnu_jHfQbM
I have 2 questions:
Question 1: among these two solution candidates, which is the better one, or say professional standard solution? or is there any other solution?
Question 2: as to both the given solution candidate, in any case we need to retrieve the referenced Language POJO at least in the corresponding controller class. But from the perspective of OO-design principle, this way seems to be tightly coupled with the controller, so I am thinking that should we decouple this retrieval behavior somewhere else than in controller? for instance in the service layer. But is this the professional way? and we need to have a corresponding DTO?
In my opinion the data which should be saved has to be nested in the body. Spring could map the json data directly into an object and you don't have to set it from parameter to another model class.
And i would create separate model classes for your entities. So the controller fills the data to the model classes and give them to a service. Then the service maps the model classes to entities. After that they could be stored via repositories.
Example:
#Controller
public class RestController {
#Autowired
RestService restService;
#PostMapping(value="/")
public void saveVariable( #RequestBody TestModel testModel ) {
testService.saveTest( testModel );
}
}
#Service
public class RestService {
#Autowired
TestRespository testRepository;
public void saveTest( TestModel testModel ) {
TestEntity testEntity = new TestEntity();
//some mapping from testModel to testEntity
testRepository.save( testEntity );
}
}
Assuming that words belong to a language, I would design it as following:
POST /api/languages/en/words HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"word": "hello"
}
Where a representation of a word (a JSON document, for example) is sent in the request payload to a URL that represents a hierarchy (a language has words).
You also could use two-letter codes to identify the languages, since it's the way clearer than numeric values. In the above example, en means English.
I advise you to avoid exposing persistence entities in your REST API and use DTOs instead. Your REST resources representations don't need to have the same attributes as the persistence objects.
Keep your REST controllers as lean as possible and keep your service layer focused on business rules.

Jersey annotation #Path with empty value on class level do not work

I declared a rest service by adding #Path("/") on class level and then on method level I declared another #Path("cars"). It doesn't seem to find the service method unless the #Path() on the class level is not empty.
Any ideas why this can't happen?
if the code is like the following
#Path("/cars")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public interface CarService {
#POST
void create(Car car);
}
it works.
If it is like the below
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public interface CarService {
#POST
#Path("/cars")
void create(CarDto car);
}
it doesn't.
Few things you should aware while writing resource code,
1.You must use the appropriate method like get,post or put based on operation otherwise it throw 405 error.
2.You must specify a unique path to all otherwise it would conflicts. Having a method name as path name is better idea.
3.You should declare the produce and consume type appropriately.
Good luck, code well.

How to do XSS escaping on input coming into Restlet web service

I have a GWT web application using Restlet.
It has #Post annotated service methods that take a bean and perform some logic on it.
I want to XML-escape the data in these beans.
For example, say I have the following:
public class MyService extends ServerResource {
#Post
public DataBean performLogic(DataBean bean) {
...
}
}
public class DataBean {
String data;
}
Is there a way I could XML-escape DataBean.data after it's serialized but before it is sent to MyService.performLogic()?
You can override the doInit() method, this may allow you do do what you need; but will occur before any calls to your #Post #Get method in your ServerResource.
Alternatively if you need it more widely you may want to look at adding a Filter into your Command Chain and overriding the beforeHandle() method there.

Serialization Exception while making an RPC call

I have created a very basic application. I have only one service class and a corresponding Async class which contains only Java types and no custom classes. But still I get the serialization exception.
My service class looks like this.
public interface MyService extends RemoteService {
public String getName();
public Object getAdditionalDetials(ArrayList<String> ids);
public Date getJoiningDate();
}
My async interface looks like this
public interface MyServiceAsync {
public void getName(AsyncCallback<String> callback);
public void getAdditionalDetials(ArrayList<String> ids, AsyncCallback<Object> callback);
public void getJoiningDate(AsyncCallback<Date> callback);
}
I know I am making some stupid mistake.
I am Naive in gwt rpc and serialization mechanism, but will try to answer your question.
Whenever you write classes involving an RPC, GWT creates a Serialization Policy File. The serialization policy file contains a whitelist of allowed types which may be serialized.
In your Service methods, all the types you mention and refer will be automatically added to this list if they implements IsSerializable. In your case you have used the following two methods,
public String getName();
public Date getJoiningDate();
Here you have used String and Date as your return types and hence it is added to your Serialization Policy File. But in the below method their lies a problem,
public Object getAdditionalDetials(Arraylist<String> ids);
Here you have used ArrayList and String that is not a problem and they will be added to your whitelist, but the problem is you have mentioned return type as Object. Here GWT Compiler does not know what type to be added to whitelist or Serialization Policy and hence it wont pass your RPC call. The solution is use mention a class which implements IsSerializable instead of mentioning the return type of type Object.
FWIW, I was having this problem but my 'Object' type was hidden behind generified classes.
So if one of your rpc methods involves a class:
class Xxx<T> implements IsSerializable {...
It needs to change to:
class Xxx<T extends IsSerializable> implements IsSerializable {...

Why are static GWT fields not transferred to the client?

ConfigProperty.idPropertyMap is filled on the server side. (verified via log output)
Accessing it on the client side shows it's empty. :-( (verified via log output)
Is this some default behaviour? (I don't think so)
Is the problem maybe related to the inner class ConfigProperty.IdPropertyMap, java.util.HashMap usage, serialization or some field access modifier issue?
Thanks for your help
// the transfer object
public class ConfigProperty implements IsSerializable, Comparable {
...
static public class IdPropertyMap extends HashMap
implements IsSerializable
{
...
}
protected static IdPropertyMap idPropertyMap = new IdPropertyMap();
...
}
// the server service
public class ManagerServiceImpl extends RemoteServiceServlet implements
ManagerService
{
...
public IdPropertyMap getConfigProps(String timeToken)
throws ConfiguratorException
{
...
}
}
added from below after some good answers (thanks!):
answer bottom line: static field sync is not implemented/supported currently. someone/me would have to file a feature request
just my perspective (an fallen-in-love newby to GWT :-)):
I understand pretty good (not perfect! ;-)) the possible implications of "global" variable syncing (a dependency graph or usage of annotations could be useful).
But from a new (otherwise experienced Java EE/web) user it looks like this:
you create some myapp.shared.dto.MyClass class (dto = data transfer objects)
you add some static fields in it that just represent collections of those objects (and maybe some other DTOs)
you can also do this on the client side and all the other static methods work as well
only thing not working is synchronization (which is not sooo bad in the first place)
BUT: some provided annotation, let's say #Transfer static Collection<MyClass> myObjList; would be handy, since I seem to know the impact and benefits that this would bring.
In my case it's rather simple since the client is more static, but would like to have this data without explicitely implementing it if the GWT framework could do it.
static variables are purely class variable It has nothing to do with individual instances. serialization applies only to object.
So ,your are getting always empty a ConfigProperty.idPropertyMap
The idea of RPC is not that you can act as though the client and the server are exactly the same JVM, but that they can share the objects that you pass over the wire. To send a static field over the wire, from the server to the client, the object stored in that field must be returned from the RPC method.
Static properties are not serialized and sent over the wire, because they do not belong to a single object, but to the class itself.
public class MyData implements Serializable {
protected String name;//sent over the wire, each MyData has its own name
protected String key;
protected static String masterKey;//All objects on the server or client
// share this, it cannot be sent over RPC. Instead, another RPC method
// could access it
}
Note, however, that it will only be that one instance which will be shared - if something else on the server changes that field, all clients which have asked for a copy will need to be updated