I have to convert a XML using gson library into a JSON
i havenĀ“t found how to do it using gson library(java)
You could use Jackson to do this:
import these libraries:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.1</version>
</dependency>
then do this in your class:
public class Example {
private String name;
private int number;
}
Example example = new XmlMapper().readValue(xml, Example.class);
String json = new ObjectMapper().writeValueAsString(example);
Related
I want to return a list of enums from a rest api call, and have it show the value of the enum rather than just the enum names, in JSON format. Currently my rest call returns json looking like:
{
"responses": [
"ACTION_TAKEN",
"IGNORED",
"UNDETECTED"
]
}
But, I want it to be more like (or something like this):
{
"responses": [
{
"name":"ACTION_TAKEN",
"value":"Action Taken"
},
{
"name":"IGNORED",
"value":"Ignored"
},
{
"name":"UNDETECTED",
"value":"Undetected"
}
]
}
My enum looks like:
public enum Response {
ACTION_TAKEN ("Action Taken"),
IGNORED ("Ignored"),
UNDETECTED("Undetected");
private String value;
Response(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
#Override
public String toString() {
return value;
}
}
My model object looks like this. For the sake of this example, it just has a list of enum values.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class StaticData {
private List<Response> responses;
public List<Response> getResponses() {
return responses;
}
public void setResponses(List<Response> responses) {
this.responses = responses;
}
}
The web service method looks like:
#Component
#Path("staticData")
#Produces("application/json")
#Consumes("application/json")
public class StaticDataResource {
#GET
public Response getCurrentContent() {
StaticData staticData = new StaticData();
staticData.setResponses(Arrays.asList(Response.values()));
return Response.ok(staticData).build();
}
}
Here are the dependencies from my effective pom (sorry for the bad formatting)
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.19.1</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.19</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
I have tried adding #JsonFormat(shape = JsonFormat.Shape.Object) to the top of my enum class. It didn't work. I tried adding #JsonValue to above my getValue() method in the enum class, and that didn't work either. I tried adding a custom serializer extending StdSerializer or JsonSerializer, and referencing that class above my enum using #JsonSerialize(using = ReasonSerializer). I put a breakpoint in the serialize method and didn't hit it, so that didn't work. I looked a little bit at doing implements ContextResolver<ObjectMapper>, but couldn't quite figure that out, or whether that was even the right path to go down or not.
Any help is greatly appreciated! Thanks!
Final solution
This works with JAX-RS and I have tested it with your code.
Use #JsonFormat with public String getName().
#JsonFormat(shape=JsonFormat.Shape.OBJECT)
public enum Response {
ACTION_TAKEN ("Action Taken"),
IGNORED ("Ignored"),
UNDETECTED("Undetected");
private String value;
Response(String value) {
this.value = value;
}
// Getters, Setters
public String getName() {
return name();
}
}
JSON output
{
"responses": [{
"value": "Action Taken",
"name": "ACTION_TAKEN"
}, {
"value": "Ignored",
"name": "IGNORED"
}, {
"value": "Undetected",
"name": "UNDETECTED"
}
]
}
Tested using the following dependency.
import com.fasterxml.jackson.annotation.JsonFormat;
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
Alternative solution
Jackson docs states that behavior may change depending on what serializer is being used. So if the first solution doesn't work, this one might.
#JsonFormat(shape=JsonFormat.Shape.OBJECT)
public enum Response {
ACTION_TAKEN ("Action Taken"),
IGNORED ("Ignored"),
UNDETECTED("Undetected");
private String name;
private String value;
Response(String value) {
name = name();
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
}
According to this page:
https://www.javaworld.com/article/2072870/java-enums-are-inherently-serializable.html
Every Enum is naturally serializable, so yours should work too.
But, you should consider what was said here:
Is custom enum Serializable too?
Summary:
"Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form"
To solve your problem I would consider using a simple Pojo class to represent your serializable class. If you still wants to use a Enum, then you could use a translator Pojo <-> Enum (I do not recomend doing this last option because of the redundancy, but last word should be yours depending on what you want to do with it :) ).
New Tag request: java-ee-8
It's got a new feature, called jsonb. With jsonb, I cannot get nested serialization working. See bold printed below.
So, I wrote a jaxrs-application. This application's got a messagebodywriter using jsonb:
final JsonbConfig defaultConfig = new JsonbConfig()
.withFormatting(Boolean.TRUE)
.withNullValues(Boolean.TRUE)
.withSerializers(
new QueryParamEntrySerializer(),
new ApiResponseDtoSerializer())
.withAdapters(new ResponseStatusJsonbAdapter());
final Jsonb jsonb = JsonbBuilder.create(defaultConfig);
ApiResponseDto is like following:
#Value.Immutable
#JsonbTypeSerializer(ApiResponseDtoSerializer.class)
public interface ApiResponseDto {
ResponseStatus status();
String message();
Optional<? extends Object> data();
}
ResponseStatus is an enumm and gets serialized via the above TypeAdapter just fine.
For this class I wrote the ApiResponseDtoSerializer.
#Provider
public class ApiResponseDtoSerializer implements JsonbSerializer<ImmutableApiResponseDto> {
#Override
public void serialize(
final ImmutableApiResponseDto obj,
final JsonGenerator generator,
final SerializationContext ctx) {
generator.writeStartObject();
ctx.serialize("status", obj.status(), generator);
ctx.serialize("data", obj.data(), generator);
ctx.serialize("message", obj.message(), generator);
generator.writeEnd();
}
}
Now the Optional data() shall contain an ImmutableSet of QueryParamEntry like this:
#Value.Immutable
#JsonbTypeSerializer(ImmutableQueryParamEntrySerializer.class)
public interface QueryParamEntry {
#Value.Parameter
String key();
#Value.Parameter
Optional<String> value();
}
The type adapter is this one:
#Provider
public class ImmutableQueryParamEntrySerializer implements JsonbSerializer<ImmutableQueryParamEntry> {
private static final Logger LOG = LoggerFactory.getLogger(ImmutableQueryParamEntrySerializer.class);
#Override
public void serialize(
final ImmutableQueryParamEntry obj,
final JsonGenerator generator,
final SerializationContext ctx) {
generator.writeStartObject();
LOG.debug("Writing: key = [{}].", obj.key());
ctx.serialize("key", obj.key(), generator);
ctx.serialize("value", obj.value(), generator);
generator.writeEnd();
}
}
The final output is:
{
"status": "success",
"data": [
{
"key": null,
"value": null
}
],
"message": "Returning query param values."
}
As you can see, the nested serialization did not work. Jsonb seems to find the correct type (because otherwise it wouldn't serialize an object at all). But even the log statement from my SerializerClass is never called.
Btw: You need Guava 22 and immutables.github.io to compile this code, and slf4j obviously:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
<version>3.0.2.Final</version>
<scope>provided</scope>
</dependency>
<!-- JSON-P API -->
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.json.bind/javax.json.bind-api -->
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.immutables</groupId>
<artifactId>value</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
So here is what it takes to make it work.
I got rid of the custom Serializers. As mentioned in my comment, they are broken before the unreleased version 1.0.3 anyway.
Instead, rename your methods to getStatus(), getMessage() and getData() (notice the get-Prefix).
For getData();, return just an Optional<Object>, not Optional<? extends Object>. Otherwise, immutables will refuse the special treatment of Optional.
After that, all just worked nicely.
I have a user list class and an API that returns user list and total records.
The class is as follows :
#JsonInclude(JsonInclude.Include.NON_NULL)
public class FMSResponseInfo {
#JsonProperty("status")
private String status;
#JsonProperty("message")
private String message;
#JsonProperty("data")
private Object data;
#JsonProperty("status")
public String getStatus() {
return status;
}
#JsonProperty("status")
public void setStatus(String status) {
this.status = status;
}
#JsonProperty("message")
public String getMessage() {
return message;
}
#JsonProperty("message")
public void setMessage(String message) {
this.message = message;
}
#JsonProperty("data")
public Object getData() {
return data;
}
#JsonProperty("data")
public void setData(Object data) {
this.data = data;
}
}
#JsonInclude(JsonInclude.Include.NON_NULL)
public class UserListResDTO {
#JsonProperty("users")
private List<UserDTO> users;
#JsonProperty("totalRecords")
private long totalRecords;
public List<UserDTO> getUsers() {
return users;
}
public void setUsers(List<UserDTO> users) {
this.users = users;
}
public long getTotalRecords() {
return totalRecords;
}
public void setTotalRecords(long totalRecords) {
this.totalRecords = totalRecords;
}
}
I am setting an object of type UserListResDTO in FMSResponseInfo as shown below.
I have been successful in creating web services and returning response as json, so far. But the problem I am facing is that the API returns the response as follows :
{"data":"org.package.UserListResDTO#70783307","message":"Success","status":"200"}
And this is how I have written the web service :
#Path("/getUsers")
#GET
#Produces(MediaType.APPLICATION_JSON)
public FMSResponseInfo getUsers(#QueryParam("page") #DefaultValue("0") int page) {
System.out.println("In getUsers()");
FMSResponseInfo fmsResponseInfo = new FMSResponseInfo();
try {
UserListResDTO userList = fmsUserManager.getAllUsers(page);
fmsResponseInfo.setData(userList);
fmsResponseInfo.setStatus(FMSErrorMessageEnum.SUCCESS_CODE.getValue());
fmsResponseInfo.setMessage(FMSErrorMessageEnum.SUCCESS_MESSAGE.getValue());
} catch (Exception e) {
return FMSUtil.getErrorResponseInfo(FMSErrorMessageEnum.INTERNAL_SERVER_ERROR_CODE.getValue(),
e.getMessage());
}
System.out.println("Out getUsers()");
return fmsResponseInfo;
}
I guess there is some problem with the dependencies or something that I am unable to resolve. Major dependencies in my pom are :
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
and I am creating Web services by extending Application class as follow :
#ApplicationPath("rest")
public class FMSApplication extends Application {
public Set<Class<?>> getClasses(){
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(FMSUserManagerWebService.class);
set.add(FMSDocumentManagerWebService.class);
set.add(FMSInboxManagerWebService.class);
set.add(FMSLocationManagerWebService.class);
return set;
}
}
Any help will be really appreciated as I am new to this REST web services and have been stuck for quite long.
This link will explain the answer
https://jersey.java.net/documentation/latest/media.html#d0e7963
9.1.1.1. POJO support
POJO support represents the easiest way to convert your Java Objects
to JSON and back.
Media modules that support this approach are MOXy and Jackson
The link to Jackson includes
9.1.4.1. Dependency
To use Jackson 2.x as your JSON provider you need to add
jersey-media-json-jackson module to your pom.xml file
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.22.2</version>
</dependency>
I don't know much about moxy but you had jackson on your CLASSPATH and were using Jackson annonations. Jersey however was configured to use moxy.
From link
JSON binding support via MOXy is a default and preferred way of
supporting JSON binding in your Jersey applications since Jersey 2.0.
When JSON MOXy module is on the class-path, Jersey will automatically
discover the module and seamlessly enable JSON binding support via
MOXy in your applications.
MOXy seemed to have handled FMSResponseInfo. Why it didn't handle the other object I do not know. But since you wanted to use Jackson you should have been using the Jackson module.
As suggested by Shire Resident in the comments using the following dependency I was able to resolve the problem :
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.22.2</version>
</dependency>
Is it a nice practice to retrieve a JSON object as a String and then parse it manually inside the application or there is a better way to get a transfer object representation (eg. some tools or comfortable APIs, automated mapping services, don't know)?
Example:
#POST
#Path("/myUrlPath")
public Response postSomething(String jsonAsString) {
JSON json = getFromMyCustomParser(jsonAsString);
MyObject myObject = getFromMyCustomMapper(json);
//business logic
}
Don't know much about this topic.
You can actually accept a JSON as a parameter of your resource method. The Jersey REST API would support this. You might have to add a JSON library as a dependency.
I think that this is the JSON dependency we use:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
In this case we use the JSONObject class from org.codehaus.jettison.json.
There's a tutorial on how to do this using the Jersey framework. It explains POJO mapping which is based on Jackson. You may have to configure POJO mapping yourself.
Heres an example for Jackson:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new Something("Name")));
public class Something {
private String name;
public Something(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Output: {"name":"Name"}
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.1</version>
</dependency>
Further reading: Jackson
Example for org.json.JSONObject:
JSONObject json = new JSONObject();
List<Object> list = new ArrayList<>();
list.add("Hello");
list.add("Hello2");
list.add("Hello3");
json.put("List", list);
System.out.println(json.toString());
Output: {"List":["Hello","Hello2","Hello3"]}
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
Further reading: JSON.org
Example for GSON
(https://sites.google.com/site/gson/gson-user-guide#TOC-Object-Examples)
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
Deserialization
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
Output: {"value1":1,"value2":"abc"}
Further reading: GSON
I'm using a java.util.Date in spring(3.1) data REST. How can I get the date to print in a human readable form? (e.g. MM/DD/YYYY)?
#Entity
public class MyEntity{
...
#Column(name="A_DATE_COLUMN")
#DateTimeFormat(iso=ISO.DATE)
private Date aDate;
..getters and setters
}
However when i print my entity(after overriding toString), I'm always getting the date as a long. It seems like #DateTimeFormat does not change the behaviour. I also tried different iso formats and that didnt help either.
"aDate" : 1320130800000
Here is my POM file entry for the spring data rest
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>1.0.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId></groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
Any help is much appeciated.
PS. Here is the toString Implementation
#Override
public String toString() {
return getClass().getName() + "{"+
"\n\taDate: " + aDate
+ "\n}";
}
looks like you will need to write a custom serializer to make Jackson (the JSON library spring uses under the hood) properly serialize the date out to text.
your getter will then look like this (where JsonDateSerializer is the custom class)
#JsonSerialize(using=JsonDateSerializer.class)
public Date getDate() {
return date;
}
check out this blog post that includes code for the serializer. The serializer code is replicated here, but the explanation in the blog post may help.
/**
* Used to serialize Java.util.Date, which is not a common JSON
* type, so we have to create a custom serialize method;.
*/
#Component
public class JsonDateSerializer extends JsonSerializer<Date>{
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
#Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String formattedDate = dateFormat.format(date);
gen.writeString(formattedDate);
}
}