UUID
A universally unique identifier (UUID) is a 128-bit value. Represented in Java by the java.util.UUID class.
Hex string
For display and for serialization, it is canonically formatted as a 36-character hexadecimal string arranged in five groups delimited by a hyphen. For example:fd95cb46-8ec3-11e8-9eb6-529269fb1459
When serializing using the Java-standard XML & JSON APIs I expect this hex string. Worked for XML, but failed for JSON. I am using no annotations of any kind for either XML or JSON. My simple POJO knows nothing of XML nor JSON.
XML = success đź‘Ť
When I produce XML using the standard XML-binding framework of JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0, success. I get the hex string as expected. See last element of this snippet:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<panel>
<connected>3.4kVA</connected>
<fedFrom>PANEL 'EHE1' & ATS-EM</fedFrom>
<grounding>ground bus</grounding>
<id>89d14b92-35ae-4c0c-b61d-ea8dbdeb324b</id>
JSON = fail đź‘Ž
When I run that same panel object through the standard JSON-binding framework of JSR 367: JavaTM API for JSON Binding (JSON-B), failure. Instead of the expected hex string, I get numbers.
{"connected":"3.4kVA","fedFrom":"PANEL 'EHE1' & ATS-EM","grounding":"ground bus","id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684},
If you scroll over, you will see the UUID named id is presented as a pair of numbers rather than as a hex string:
"id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684}
Is there some way to get the JSON binding to behave as the XML binding does? I want the hex string, not a pair of 64-bit numbers.
And of course this marshaled value should work when unmarshaled, re-hydrated into a Java object.
The JSON-B spec makes no mention of the UUID type, so it's up to the implementation whether or not it provides a (de)serializer out of the box. However, if you are using Eclipse Yasson (the JSON-B ref impl), it does provide a UUID (de)serializer by default. I'm not sure what other JSON-B impls (such as Apache Johnzon) provide by default.
If you are using Yasson, I would recommend opening a bug on their GitHub repo, because this should work.
Custom way
If you are using a JSON-B implementation that does not provide UUID adapters by default, you can create and register your own type adapter:
public static class MyUUIDAdapter implements JsonbAdapter<UUID, String> {
#Override
public String adaptToJson(UUID obj) throws Exception {
return obj.toString();
}
#Override
public UUID adaptFromJson(String obj) throws Exception {
return UUID.fromString(obj);
}
}
The easiest way to register the adapter is when you create the Jsonb instance:
Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new MyUUIDAdapter()));
However, if you don't control instantiation of your Jsonb instance (e.g. JAX-RS is doing it under the covers) you can annotate the field/method to use the adapter on:
public class Panel {
#JsonbTypeAdapter(MyUUIDAdapter.class)
public UUID id;
}
Related
The few times I've worked with Java/Rest/JSon, JSON elements have always been built in camelCase format.
For example:
"someField": {
"someSonField1": "20191106",
"someSonField2": "20201119",
...
}
However, in a functional document they have passed me to build a Rest JSon client, they use this notation:
"some_field": {
"some_son_field_1": "20191106",
"some_son_field_2": "20201119",
...
}
Is it expressed somewhere that Java has to use the notation 1?.
It seems to me that if it is done this way, everything goes much more smoothly when modeling the objects:
#XmlRootElement(name = "someField")
#XmlType(propOrder = {"someSonField1", "someSonField2"})
public class someField {
private String someSonField1;
private String someSonField2;
//...
}
Thanks!
Q: Is it expressed somewhere that Java has to use the notation?
A: No: it's 100% "convention", not mandatory.
As it happens, the standard convention for both JSON (a creature of Javascript) and Java is camelcase. For example: Java Naming Conventions.
some_son_field_1 is an example of snake case. It's associated with classic "C" programs. It's also common (but NOT universal) with XML. It, too, is a "convention" - not a requirement.
I'm curious why you're choosing XML bindings for JSON data. Have you considered using Jackson?
Finally, this article might be of interest to you:
5 Basic REST API Design Guidelines
I see you're using javax.xml.bind package? Have you tried #XmlElement?
#XmlRootElement(name = "someField")
#XmlType(propOrder = {"some_son_field_1", "some_son_field_2"})
public class someField {
#XmlElement(name="some_son_field_1")
private String someSonField1;
#XmlElement(name="some_son_field_2")
private String someSonField2;
//...
}
Not sure, probably you should try putting them on getters, as your fields are private.
Or you could use unify-jdocs, a library which I created to read and write JSON documents without using any POJO objects. Rather than defining POJO objects, which we know can be difficult to manage in case of complex documents and changes to the JSON document, just don't use them at all. Directly read and write paths in the JSON document. For example, in your snippet, you could read and write the fields as:
Document d = new JDocument(s); // where s is a JSON string
String s1 = d.getString("$.some_field.some_son_field_1");
String s2 = d.getString("$.some_field.some_son_field_2");
You could use a similar way to write to these paths as so:
d.setString("$.some_field.some_son_field_1", "val1");
d.setString("$.some_field.some_son_field_2", "val2");
This library offers a whole lot of other features which can be used to manipulate JSON documents. Features like model documents which lock the structure of documents to a template, field level validations, comparisons, merging documents etc.
Obviously, you would consider it only if you wanted to work without POJO objects. Alternatively, you could use it to read and write a POJO object using your own method.
Check it out on https://github.com/americanexpress/unify-jdocs.
I am using a Web service and it returns a String value. But in my output, that value is in XML format:
String point = request.getParameter("point");
try {
String latLonListCityNames = proxy.latLonListCityNames(new BigInteger(point));
request.setAttribute("point", latLonListCityNames);
System.out.println(latLonListCityNames);
} catch (RemoteException e) {
e.printStackTrace();
}
I expect the output to be for example "Oklahoma", but the actual output is:
<?xml version='1.0' ?>
<dwml version='1.0' xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
<latLonList>
<cityNameList>
Oklahoma
</cityNameList>
</dwml>
The responses of web-services are commonly (not always) in XML. If you need to extract the data from xml string response to your desired format, say, Java Objects (POJO), you need a converter i.e. marshaling and Un-marshaling of data.
Simple solution
Use JAXB.
What is JAXB? From wiki
Java Architecture for XML Binding (JAXB) is a software framework that allows Java developers to map Java classes to XML representations. JAXB provides two main features: the ability to marshal Java objects into XML and the inverse, i.e. to unmarshal XML back into Java objects.
How does it fit into my use-case?
Create a simple POJO for the type of response you are expecting. And then use JAXB convertor to convert them for you.
Eg. If you are expecting a list of cityName in response, you can create your POJO like below..
CityModel.java
public Class CityModel {
private List<String> cityName;
// if more field required, add here.
}
Sample XML response should be..
<ListOfCities>
<CityName>My City</CityName>
<CityName>Your City</CityName>
<CityName>So Pity</CityName>
</ListOfCities>
Then, pass this xml response string to JAXB binding for Equivalent Class type. i.e. CityModel.
How to do all this? Can You Share some good example?
Read this tutorial to get started.
I have problem with the response type names, they are not well described, how can I map them with different name that I want?
You might need to look at links below, they key part is investigate more about #XmlRootElement, #XmlAttribute, #XmlElement, etc annotations for custom configurations.
Few more important links that can help later on?
Convert Soap XML response to Object
convert xml to java object using jaxb (unmarshal)
Using JAXB for XML With Java
JAXB Unmarshalling Example: Converting XML into Object
I'm incredibly new to Jackson and I have a problem with understanding how I could accomplish something.
I've got some data that is of type byte[] (the data is within classes generated from JAXB). Before the data is sent to the browser, Jackson then (I believe) turns it into JSON so that the webpage can consume it. At least that is my crude understanding, so far.
The JSON data shows my byte [] as strings, which don't match the display that we want. For instance, the actual data might be CAFEDEAD but the JSON string looks like 3q2+78r+. I'd like the JSON to contain the string CAFEDEAD
My question is, can I write something custom for Jackson that before it creates the final JSON, turn the byte[] data into a readable hex string? Or if not, what other options do I have?
I have access to the javascript so if there is a way to turn the JSON string back, i'm up for that as well.
Jackson will convert byte[] into Base64-encoded binary data. This is the safe way to pass binary content. Otherwise there is no way to know which character encoding might be used by contained data, so trying to build a String out of it would be risky and error-prone.
So the simplest way would be to have receiver base64 decode contents back into binary data.
You could alternatively add custom serializer to turn into other representations (hex, base85), but it really depends on what the goal is.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
Below is how you could support this use case with MOXy as your JSON-binding provider.
Java Model
By default a JAXB implementation will convert a byte[] to base64Binary. You can use the HexBinaryAdapter to have it represented as hexBinary.
package forum15643723;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private byte[] foo;
#XmlJavaTypeAdapter(HexBinaryAdapter.class)
private byte[] bar;
}
Demo
In the demo code below we will read the JSON into objects and then write it back to JSON.
package forum15643723;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Root.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum15643723/input.json");
Root root = (Root) unmarshaller.unmarshal(json, Root.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
input.json/Output
The foo and bar properties represent the same data. foo is represented as base64Binary and bar is represented as hexBinary.
{
"foo" : "3q2+78r+",
"bar" : "DEADBEEFCAFE"
}
For More Information
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
You can use #JsonSerialize and #JsonDeSerialize annotations over any property. javadoc is at
http://jackson.codehaus.org/1.2.1/javadoc/org/codehaus/jackson/map/annotate/JsonSerialize.html
I would personally use the serialization/deserialization technique rather than conversion at client side as you probably end up doing it at multiple places.
Without any code, I had to guess what you are doing according to your question. This tutorial JSON parse to / from using Jackson shows you how to convert ObjectMapper to a Stringfiyed representation of JSON for example
"{"age":29,"messages":["msg 1","msg 2","msg 3"],"name":"mkyong"}"
Then when Javascript client receives this String, you are going to have to parse this using either built in JSON parse function or jQuery provided one. Like
...
var myJson = JSONString.parse() | jQuery.parseJSON(JSONString);
..
myJson.age; //29
myJson.name; //"mkyong"
Reason for attempting to parse it using parse() first is to avoid using jQuery while there is already a built in function for this provided by browser. However, if this function is not detected, it will parse it through jQuery.
I hope this helps
For your interest
Your data example appears to be some kind of binary data and you are attempting to send it over the networks. This might cause routers to filter these data. If you are interested, you can have a look at encoding this data into Base64 before streaming it to the client. It is very easy to do because there are many libraries out there already.
Some resources regarding to this topic.
So it is going to be like
SERVER
1) Jackson creates JSON String
2) Server encodes into Base64
3) Send
CLIENT
1) Receive
2) Decode base64
3) parse JSON String
I am writing a RESTful web service using Java and Jersey, where the service will accept either XML or JSON inputs. Jackson is used as the JSON deserializer, and integrated into the Jersey config.
One of the endpoints is a POST request to a URL, where the content can be one of several different Java classes, and there is a common base class. These classes - with XML annotations - are:
#XmlRootElement(name = "action")
#XmlAccessorType(XmlAccessType.NONE)
#XmlSeeAlso({ FirstAction.class, SecondAction.class, ThirdAction.class })
public abstract class BaseAction {
}
#XmlRootElement(name = "first-action")
#XmlAccessorType(XmlAccessType.NONE)
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
In my resource I can declare a method like:
#POST
#Path("/{id}/action")
public Response invokeAction(#PathParam("id") String id, BaseAction action) {...}
Then I can POST an XML fragment that looks like <firstAction/> and my method will be invoked with a FirstAction instance. So far so good.
Where I'm struggling is getting the JSON deserialization to work as seamlessly as the XML deserialization. Where the #XmlSeeAlso annotation was critical to get the XML deserialization working properly, it seemed that the equivalent for JSON was #JsonSubTypes. So I annotated the classes like this:
// XML annotations removed for brevity, but they are present as in the previous code snippet
#JsonSubTypes({ #JsonSubTypes.Type(name = "first-action", value = FirstAction.class),
#JsonSubTypes.Type(name = "second-action", value = SecondAction.class),
#JsonSubTypes.Type(name = "third-action", value = ThirdAction.class) })
public abstract class BaseAction {
}
#JsonRootName("first-action")
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
I then feed it my test input: { "first-action": null } but all I can get is:
"org.codehaus.jackson.map.JsonMappingException: Root name 'first-action' does not match expected ('action') for type [simple type, class com.alu.openstack.domain.compute.server.actions.BaseAction]"
Unfortunately since I'm trying to be compatible with someone else's API I can't change my sample input - { "first-action": null } has to work, and deliver to my method an object of class FirstAction. (The action doesn't have any fields, which is why null shouldn't be a problem - it's the type of the class that's important).
What's the correct way to have the JSON deserialization work in the same way as the XML deserialization already is?
If you are using Jackson, you are looking for #JsonTypeInfo and #Type . Please see here for more information
JSON does not work the way XML does, so the solution is not identical.
What you need to use is (like the other answer said), #JsonTypeInfo. That only triggers inclusion and use of the type identifier. If so, then '#JsonSubTypes` will be of use in deserialization.
The reason this indicator must be used is simple: if you have more than one alternative type to deserialize to, there must be something to differentiate.
Note, too, that this does NOT have to be a property -- while most users choose "As.PROPERTY" inclusion, it is not (IMO) the best way. "WRAPPER_OBJECT" may be what you are looking for, as it adds an extra intermediate JSON property, which is somewhat similar to what XML does.
I investigated the use of #JsonTypeInfo but ran into problems because I could not alter the input format. The parser absolutely had to be able to handle input { "first-action":null }. This ruled out the possibility of adding an #type or #class property. Using a wrapper object may have worked, but it choked on the null payload.
A crucial point was that I was using the UNWRAP_ROOT_PROPERTY configuration option. Jackson was absolutely insisting on finding an action property and I could not get it to consider anything else. So, I had to selectively disable UNWRAP_ROOT_PROPERTY for certain domain objects, so that Jackson would be open to parsing alternatives. I modified the project's ContextResolver.getContext(...) implementation to check for a #JsonRootName annotation - since this only has meaning if wrapping is enabled, I used the presence of this annotation to determine whether to return an object mapper configured with root property wrapping on, or off.
At this stage, I might have been able to use #JsonTypeInfo(include=JsonTypeInfo.As.WRAPPER_OBJECT, ...), except for the issue with the null payload mentioned above (this is used to indicate that the child object has no properties - if the spec I was working from had given an empty object {} instead then there would not be a problem). So to proceed I needed a custom type resolver.
I created a new class that extended org.codehaus.jackson.map.TypeDeserializer, with the purpose that whenever Jackson is called to deserialize a BaseAction instance, it will call this custom deserializer. The deserializer will be given a subtypes array, which for BaseAction maps first-action, second-action, etc. to FirstAction.class, etc. The deserializer reads the input stream for the field name, then matches the name to a class. If the next token is an object, then it finds and delegates to the appropriate deserializer for that class, or if it is null it finds the no-args constructor and invokes it to get an object.
A class that implements org.codehaus.jackson.map.jsontype.TypeResolverBuilder is needed that can build an instance of this previous class, and then the TypeResolverBuilder is given as a #JsonTypeResolver annotation on the BaseAction class.
I am trying to create a webservice which takes a VO and VO contains a parameter of type Map. I wrote this simple Service and trying to create the webservice out of it. While creating the webservice I am getting exception that its not supported.
public MyVO myService(MyVO vo) {
return vo;
}
public class VO{
private String name;
private Map<String, Serializable> paramsMap;
}
Error Which I am getting :
The field or property on the value type used via the service class has a data type, "java.util.Map", that is not supported by the JAX-RPC 1.1 specification. Instances of the type may not serialize or deserialize correctly. Loss of data or complete failure of the Web service may result.
I am not sure what's wrong with this. Any help or work around?
thanks in advance.
This link shows the data types supported by JAX-RPC 1.1 and Map (and all its subclasses aren't supported).
JAX-RPC 1.1 Specification, section 5.1.3 states:
Other standard Java classes (for
example: classes in the Java
Collection Framework) are mapped using
pluggable serializers and
deserializers. Refer to the chapter 15
(“Extensible Type Mapping”) for more
details on the pluggable serializers
and deserializers.
One workaround is to have an array of key/value pair JavaBean that you can pass through a parameter.
Example:
public final class KVPair<T> implements Serializable {
private String key;
private T value;
//Getters and setters
}
And have a service that has a map of KVPair.
service.consume(KVPair[] map);
IBM DeveloperWorks shows examples of mapping arrays as a Complex Type in WSDL.