I have some sensitive domain objects that I would like to convert to json and xml. I am using spring view resolution to do this, but that is beside the point.
I'd like to add annotations to the domain objects to specify which fields should be converted to xml / json.
Something like
#XmlRootElement
public class SensitiveDomainObject {
...
public String getPassword() {...}
#XmlAttribute
#JsonValue
public String getAccountName() {...}
#XmlAttribute
#JsonValue
public String getGoldMemberStatus() {...}
}
I want getAccountName() and getGoldMemberStatus() to be serialised to json and xml, but getPassword to never be serialised.
What I don't want is
1) Separate 'annotation placement strategies' for json and xml as that gets confusing if one needs to markup different methods in different ways as standard.
2) To be explicitly ignoring fields. This is because if some programmer comes along in the future and adds a newly sensitive field without including for example the #JsonIgnore annotation, suddenly that sensitive field is shared.
3) To have to make methods like getPassword() private. I still want to be able to call getPassword() internally.
Has anyone done this or have any thoughts?
EDIT
Included a picture from IBM showing essentially the design I ran with, with explicit DTOs with annotations in the business logic layer. The presentation layer figures out which DTO to request and serve based on the incoming URL.
If you care so much about differentiating what you your business classes are and what is transferred, you may consider implementing a separate package of DTO classes which will explicitly include only those properties you'd like to transfer.
In this case you'll have to explicitly include the transfer properties, this can't happen because the programmer forgot it.
There are other approaches to this like adding some validation rules that the property like password is ignored and enforce them on JAXB context level. But this will only work until someone not knowing will name it kennwort or credentials or whatever may come in mind and your validation rules will be out of effect.
So I see two way:
* Either you trust the programmer (and all the QA/QS process like code reviews etc.) to support her/him.
* Or you make your transfer classes explicit.
For important external interfaces I'd probably go with the second approach (explicit DTOs). If password ends up there, it can't be by forgetting, it will only be on purpose.
Related
Which annotate the relationship allow Jackson to better handle the relation, for save Click ? How change request:
{ "idBanner": 2, "fullnameClient": "Maria"}
#JsonManagedReference, #JsonBackReference,#JsonIdentityInfo,#JsonIgnore...
Working format-request (save Click):
#RequestParam is used to map just request parameters. For example, it will work for requests like POST /sentemail?fullnameClient=vov&idBanner=1
To get request body you should use #RequestBody annotation.
Important notice
I would recommended don't use models (entities) for requests and responses, because it increases a coupling between your business logic and external contract Rest API. For example, in future you will not able to change model without changing of external contract and vise versa.
But if you still want to use entities as request/response body, I would recommend taking a look on Jackson MixIns. It helps to have separate mapping for Jackson and Entities.
I have a resource that has a public and a private response, and only some users in determinant situations can access the private response.
What would be the best implementation?
Two urls, one for the public and another for the private: resource/{id} and resource/{id}/private.
Same url, different response for each user: resource/{id}.
Same url with and a parameter that different the public and private: resource/{id}?private=true.
Other?
Your terminology is a little mixed up. You have one resource, and multiple representations. The resource should have one canonical location (URL). It's perfectly fine for different users to get different representations based on their auth level.
If you want a user to be able to request a specific representation of the resource, you have a couple of options. If you're using custom MIME types, the Accept header would be the best choice. A query parameter is your best bet if you're not using custom MIME types, but make sure it's something generic and consistent throughout the application. Don't just use ?private=true, but instead use something like ?representation=public. That allows you to add representations later and use the same parameter, and share the same query parameter with other resources that need to specify a representation. You should avoid using a separate URL.
IMO one resource should have only one URL. You can make use of auth-token in HTTP to check if the server should respond with a private response or a public response. Also if some user is requesting for some unauthorized resource, you can send a 4xx status.
Thus resource/{id} seems like a good choice.
I am aware of [JsonIgnore] attribute. Unfortunatelly it ignores property on both, the Request and the Response.
I need a way to ONLY ignore it during RESPONSE. Having to work with two different classes for request and response (even by using inheritance) is not an acceptable solution as it introduces a whole a lot of object copying hassle.
Any help is appreciated.
JsonIgnore instructs the JsonSerializer not to serialize the public field or public read/write property value for both request and response.
It sounds like you have a design issue. Create your request/response data contracts separately and more properly.
In my grails application I want to render hierarchy of objects as JSON response. There are several properties of java.util.Date type, specified on different levels, having different names. Depending on the location and name, I want to render date differently, something like this:
{
...
"touristBirthday": "1980-10-11",
"flight": {
...
"flightTime": "2013-10-11 10:00",
...
}
...
}
Note that touristBirthday and flightTime have both java.util.Date type, but should be rendered differently. So grails object marshaller is not really useful for me.
In some parts of the application I've already done conversion manually by transforming my model beans into maps and then overriding entries in these maps, but doing this in each case produces lots of unmaintainable mess, especially when the hierarchy has many levels.
Is there any plugin or simple solution to this problem? So I can simply specify name/location of my property and the way to render it, overriding default object marshaller.
P.S. changing the model (property types) is not really an option for me, as the model comes from another application.
from Jersey a classic JSON output of List looks like:
{"SubtaskType":{"id":"4","name":"mozaika","metric":"m2","code":"104"}}
But GSON will say it's not a JSON array and experimentally, it accepts:
{"id":"4","name":"mozaika","metric":"m2","code":"104"} for single SubtaskType.
I tested it with JSON validator and it seems that both forms are acceptable.
GSON's output of List looks like:
[{"name":"aa","metric":"m2","id":1,"code":200},{"name":"bb","metric":"m","id":2,"code":300}]
Is there a way to configure GSON to parse/generate the longer form (with type name)?
Edit:
This is the structure (added for change/discussion):
public class SubtaskType {
private int id;
private String name;
private String metric;
private int code;
//getters & setters
}
Note: This answer is based on the original version of the question.
from Jersey a classic JSON output of List looks like:
{"SubtaskType":{"id":"4","name":"mozaika","metric":"m2","code":"104"}}
Really? That's not a JSON array, i.e., list. It's an object with one element named "SubtaskType", for which the element's value is an object with four elements. There is no list.
Is that just what a list with a single component comes out like? Does a list with two components come out like
{"SubtaskType":[{"id":"4","name":"mozaika","metric":"m2","code":"104"},{"name":"bb","metric":"m","id":2,"code":300}}
If this is the case, and you must receive such poorly-generated* JSON, and you must use Gson, then you'll have to implement custom deserialization processing to handle the situation where it's sometimes a list and it's sometimes an object. This is an all-too-often occurring problem. Gson unfortunately does not yet have a simple configuration available to handle this often-occurring problem. I posted an example of such custom deserialization processing in response to the question at Parsing JSON with GSON, object sometimes contains list sometimes contains object
* Just because it's valid JSON, doesn't mean it's not crap. An API should generate consistently-structured JSON. Anything less is crap.
GSON's output of List looks like:
[{"name":"aa","metric":"m2","id":1,"code":200},{"name":"bb","metric":"m","id":2,"code":300}]
Good. That's what a list in JSON is supposed to look like.
Is there a way to configure GSON to parse/generate the longer form (with type name)?
Yes. The specific solution depends on what your Java data structure currently looks like, and whether you're able to change the structure to match the desired JSON. If you cannot change the Java data structure accordingly, then you must custom process serialization/deserialization. Post the Java data structure you'd like to use, and indicate whether it can be changed.
Also, post an exact example of the "longer form" JSON you want to generate that represents a list with at least two components. You have not done this, yet. So, it leaves me guessing about what you really want to do.
It does seem pretty clear that you want polymorphic type handling in whatever the ultimate solution is. This will require custom deserialization processing, if using Gson.
Regarding any question on polymorphic deserialization, please note that the issue was discussed a few times on StackOverflow.com already. I posted a link to four different such questions and answers (some with code examples) at Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied.
For polymorphic serialization, not only will it likely be necessary to implement custom serialization to generate the desired type element, but convincing Gson to serialize all of the fields from polymorphic types also requires custom processing. See Serializing List of Interfaces GSON for more information.