I have the following object and its value is set via a REST call as follows.
#Getter
#Setter
public class Benefit {
#JsonProperty("text")
private String headerText; // To note, I can't modify this headerText name
}
Data set from a rest call.
ResponseEntity<Benefit> response =
template.exchange(url, HttpMethod.POST, request, Benefit.class);
Benefit benefit = response.getBody();
The return value from the rest call is in following format which is why I annotated it as text.
{
"text" : "some text"
}
After this, using this response, I am passing it down as a value to the client that called me.
But when I send the information down, I don't want to name it as text.
I want to call it as description. Thus my response will be as follows:
{
"description" : "some text"
}
Queries/ Pointers
1. Is there a way to do this without me having to manually set it?
2. This headerText is in use for different REST call. In that scenario, I need to both
receive the value as text and also return as text. (Thus that has no issues).
3. Preferably any possible solutions, should not affect above point 2.
4. But is ok if it will affect. I will go with an entirely new Benefit2 Object to resolve this if there is a solution which affects point 2.
One possible way to do this is to set the value to another variable and pass that down as follows only for the particular rest call.
But finding it very cumbersome as follows.
Add a new field called description
#Getter
#Setter
public class Benefit {
#JsonProperty("text")
private String headerText;
// add a new field
private String description;
}
After the rest call, do the following:
Benefit benefit = response.getBody();
benefit.setDescription(benefit.getHeadlineText);
benefit.setHeaderText(null);
Any better ways?
To clarify on the flow:
Client calls my service
My service calls another service and got back:
{
"text" : "some text"
}
I then return the following back to the client.
{
"description" : "some text"
}
Thoughts after discussion.
Intention to use this object in both places, when calling rest and when returning response to client.
#Getter
#Setter
public class TestBenefit extends Benefit {
#Getter(AccessLevel.NONE)
#JsonProperty("text")
private String text;
private String description;
public void setText(String text) {
this.description = text;
}
}
Over time I learned that trying to use one object for multiple purposes in these scenarios is more trouble than it is worth. You should create objects that cater to your requests and responses appropriately. Use base classes if necessary. Also, I wouldn't call it Benefit2. :o) Name your classes, to some degree, for what they are used for. You could do something like...
class BenefitForOtherPurpose extends Benefit {
#JsonProperty('description')
public String getHeaderText() {
return this.headerText;
}
}
To that end, I don't think there is a way using the Jackson API to adjust the #JsonProperty value dynamically short of some reflection kung-fu that, again, is likely more trouble than it is worth. And there's nothing I know of in the Jackson API to conditionally set that outside of this complex solution:
Conditional JsonProperty using Jackson with Spring Boot
I'm working on RSS Feed using XStream library and I have following model (simplified for example purpose)
public class Item {
private String title;
private String link;
private String guid; }
And it works fine, it generates the part of the XML I need. The problem though is that I need to add custom attribute for guid ("isPermaLink") and I can't find any solution for that.
So the XML I need would be:
<item>
<title>Test</title>
<link>www.example.com/abc</link>
<guid isPermaLink="false">www.example.com/abc</guid>
</item>
I know I can make attribute by using
#XStreamAsAttribute
So I tried to add another class for GUID
public class Guid {
private String value = "http://example.com/abc";
#XStreamAsAttribute
private boolean isPermaLink = true;
}
and point to that in my Item class but then the generated code contains GUID part like this:
<guid2 isPermaLink="true">
<value>http://example.com/abc</value>
</guid2>
And I can't have this element inside. The value needs to be inline.
The question is - how can I make the value inline OR how can I add attribute to String field
Sorry for self answering but after spending some time on this topic I finally found an answer. Probably that can help someone so I'm posting it here.
Basically I think there is no default way of doing that. I went through all the tutorials on XStream and also looked at every single annotation available from XStream.
Finally I did manage to do a workaround that works. Basically in order to add an attribute to String (for example) you can use custom Converter and add an attribute there.
So on my guid field I'm using XStreamConverter to choose my converter:
#XStreamConverter(value = GuidConverter.class)
private String guid;
And the converter itself:
public class GuidConverter implements Converter{
#Override
public boolean canConvert(Class type) {
return String.class.isAssignableFrom(type);
}
#Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
String value = (String) source;
writer.addAttribute("isPermaLink", "false");
writer.setValue(value);
}
#Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
//TODO if you need - I don't because I'm only marshalling in my scenario
return null;
}
}
This a shame that there is no "out of box" solution for that because if you had more String on which you wanted attribute or you wanted make these attributes values dynamic then... well the solution is not going to work for you.
In my case it worked because I always need same value (isPermaLink="false") but in most cases that's not going to be enough.
Perhaps someone has better idea to do that
First of all, let me thank you in advance for all of your help!
Let me explain my current problem:
I'm trying to wrap some legacy web service calls with a rest/json/swagger layer. The fact is those old services use a tricky propietary xml format, which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<service_RegistroEventoSrv>
<inputMap type="map">
<mensajeMT type="map">
<identificador type="String">
<_value_>USUPRUEBA</_value_>
</identificador>
<modo type="String">
<_value_>1</_value_>
</modo>
</mensajeMT>
</inputMap>
</service_RegistroEventoSrv>
I've been able to serialize most of the objects and fields but I have a problem with the root tag. The main class used for the serialization is the following one, but I need that root tag takes its value from the "serviceId" property
public class CafRequestObject<I,O> {
private String serviceId;
private I inputMap;
private O outputMap;
private RequestMetaInfo requestMetaInfo;
private ResponseMetaInfo responseMetaInfo;
... getters and setters
}
In order to achieve that tricky and custom serialization, I have added some serializares to the jackson XmlMapper for spring rest template.
CafRequestObjectSerializer
public class CafRequestObjectSerializer extends CafXsdSerializer<CafRequestObject> {
public void serialize(CafRequestObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
final ToXmlGenerator xgen = (ToXmlGenerator) jgen;
xgen.writeStartObject();
addRequestMetaInfo(value.getRequestMetaInfo(),xgen);
addObject(value.getInputMap(), xgen,INPUT_MAP);
xgen.writeEndObject();
}
}
Is there any way to get the root name from a field value? This is mandatory in my situation, because every call must have a different root value (so no JsonRootName or XmlRootName is posssible for me)
Thanks a lot in advance!
I've finally found a solution. Maybe it is not the best, but at least works for me :)
I have extended jackson's class XmlSerializerProvider and overrided methods
serializeValue .
There is a section where code does the following stuff:
QName rootName = _rootNameFromConfig();
if (rootName == null) {
rootName = _rootNameLookup.findRootName(cls, _config);
}
I have modified it's original behaviour in order to alter the way it gets the root tag, based on the field of my root class:
QName rootName = _rootNameFromConfig();
if (rootName == null) {
if (value instanceof CafRequestObject){
rootName= getRootNameFromServiceId((CafRequestObject)value);
}
else{
rootName = _rootNameLookup.findRootName(cls, _config);
}
}
protected QName getRootNameFromServiceId(CafRequestObject object){
return new QName( object.getServiceId()+_SERVICE);
}
Thanks for your help!
Jersey by default convert single element returned to object . But the client side is expecting the data in json to be arraylist
Model class is LocationDetails
public class LocationDetails {
private String locationAccount;
private String locationName;
private String locationStreet;
private String locationPostcode;
}
other class LocationData which has arraylist of LocationDetails as
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class LocationData {
private ArrayList<LocationDetails> Locations;
}
and the controller class is using the following code to convert to JSON:
//Getting location and item along with barcodes
#POST
#Path("/getLocationAndItemData")
#Produces(MediaType.APPLICATION_JSON)
public LocationResponse getAlllocations(){
ArrayList<LocationDetails> locationDetailList = new ArrayList<LocationDetails>();
LocationDetails details = new LocationDetails();
//setting location account
details.setLocationAccount("10125");
locationDetailList.add(details);
}
The following code is returning json as LocationData : {LocationDetails : {"LocationAccount","10125"}}
whereas i want it to be like :
LocationData : {LocationDetails : [{"LocationAccount","10125"}]}
as the client side would expect the data to be inside list.
How to convert the type without changing the whole logic.I am using jersey.
Add #XmlElementWrapper annotation to your List, that should do the trick. If you have further problems with Jersey, try first XML output to see what is being produced. If XML is ok, JSON will be too.
#XmlElement(name="locationDetail")
#XmlElementWrapper(name="locationDetails")
private List<LocationDetail> locationDetails;
Also name your class properties with first lowercase letter, please.
I too had the same issue, after so many research i found that the problem is due to the jar files imported in the MyEclipse (Persisted container). I have removed that. The same code works for me.
The json format will be [{single element}].
Is there an easy way to return data to web service clients in JSON using java? I'm fine with servlets, spring, etc.
It might be worth looking into Jersey. Jersey makes it easy to expose restful web services as xml and/or JSON.
An example... start with a simple class
#XmlType(name = "", propOrder = { "id", "text" })
#XmlRootElement(name = "blah")
public class Blah implements Serializable {
private Integer id;
private String text;
public Blah(Integer id, String text) {
this.id = id;
this.text = text;
}
#XmlElement
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
#XmlElement
public String getText() { return text; }
public void setText(String value) { this.text = value; }
}
Then create a Resource
#Path("/blah")
public class BlahResource {
private Set<Blah> blahs = new HashSet<Blah>();
#Context
private UriInfo context;
public BlahResource() {
blahs.add(new Blah(1, "blah the first"));
blahs.add(new Blah(2, "blah the second"));
}
#GET
#Path("/{id}")
#ProduceMime({"application/json", "application/xml"})
public Blah getBlah(#PathParam("id") Integer id) {
for (Blah blah : blahs) {
if (blah.getId().equals(id)) {
return blah;
}
}
throw new NotFoundException("not found");
}
}
and expose it. There are many ways to do this, such as by using Jersey's ServletContainer. (web.xml)
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Thats all you need to do... pop open your browser and browse to http://localhost/blah/1. By default you will see XML output. If you are using FireFox, install TamperData and change your accept header to application/json to see the JSON output.
Obviously there is much more to it, but Jersey makes all that stuff quite easy.
Good luck!
We have been using Flexjson for converting Java objects to JSON and have found it very easy to use.
http://flexjson.sourceforge.net
Here are some examples:
public String searchCars() {
List<Car> cars = carsService.getCars(manufacturerId);
return new JSONSerializer().serialize(cars);
}
It has some cool features such as deepSerialize to send the entire graph and it doesn't break with bi directional relationships.
new JSONSerializer().deepSerialize(user);
Formatting dates on the server side is often handy too
new JSONSerializer().transform(
new DateTransformer("dd/MM/yyyy"),"startDate","endDate"
).serialize(contract);
To me, the best Java <-> JSON parser is XStream (yes, I'm really talking about json, not about xml). XStream already deals with circular dependencies and has a simple and powerful api where you could write yours drivers, converters and so on.
Kind Regards
http://www.json.org/java/index.html has what you need.
Yup! Check out json-lib
Here is a simplified code snippet from my own code that send a set of my domain objects:
private String getJsonDocumenent(Object myObj) (
String result = "oops";
try {
JSONArray jsonArray = JSONArray.fromObject(myObj);
result = jsonArray.toString(2); //indent = 2
} catch (net.sf.json.JSONException je) {
throw je;
}
return result;
}
I have found google-gson compelling. It converts to JSON and back. http://code.google.com/p/google-gson/ It's very flexible and can handle complexities with objects in a straightforward manner. I love its support for generics.
/*
* we're looking for results in the form
* {"id":123,"name":thename},{"id":456,"name":theOtherName},...
*
* TypeToken is Gson--allows us to tell Gson the data we're dealing with
* for easier serialization.
*/
Type mapType = new TypeToken<List<Map<String, String>>>(){}.getType();
List<Map<String, String>> resultList = new LinkedList<Map<String, String>>();
for (Map.Entry<String, String> pair : sortedMap.entrySet()) {
Map<String, String> idNameMap = new HashMap<String, String>();
idNameMap.put("id", pair.getKey());
idNameMap.put("name", pair.getValue());
resultList.add(idNameMap);
}
return (new Gson()).toJson(resultList, mapType);
For RESTful web services in Java, also check out the Restlet API which provides a very powerful and flexible abstraction for REST web services (both server and client, in a container or standalone), and also integrates nicely with Spring and JSON.
As already mentioned, Jersey (JAX-RS impl) is the framework to use; but for basic mapping of Java objects to/from JSON, Tutorial is good. Unlike many alternatives, it does not use strange XML-compatibility conventions but reads and writes clean JSON that directly maps to and from objects. It also has no problems with null (there is difference between missing entry and one having null), empty Lists or Strings (both are distinct from nulls).
Jackson works nicely with Jersey as well, either using JAX-RS provider jar, or even just manually.
Similarly it's trivially easy to use with plain old servlets; just get input/output stream, call ObjectMapper.readValue() and .writeValue(), and that's about it.
I have been using jaxws-json, for providing JSON format web services. you can check the project https://jax-ws-commons.dev.java.net/json/.
it's a nice project, once you get it up, you'll find out how charming it is.