I use Jackson library to generate json string like this:
ObjectMapper objectMapper = new ObjectMapper();
String str = objectMapper.writeValueAsString(model);
and this snipped code for instance generate somtething like this:
{"x" : "This is x", "y" : "This is y"}
but I want to generate something like this:
{'x' : 'This is x', 'y' : 'This is y'}
I mean how can I change the double quote string with single quote string.I try to change code like this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
String str = objectMapper.writeValueAsString(model);
but this snipped code generate the first one.
and of course I can handle this problem with replace method but I want Jackson library do this for me.
How can I handle this problem?
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); is about allowing single quotes in deserializing (JSON to Objects), not serializing (Objects to JSON) as you want.
In serializing, the issue seems to be with Jackson 1.X's default serializer. Below is the code that Jackson uses to write the String values. As you can see, the double quotes are hard coded and thus unchangeable through configuration:
#Override
public void writeString(String text)
throws IOException, JsonGenerationException
{
_verifyValueWrite("write text value");
if (text == null) {
_writeNull();
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"'; // <----------------- opening quote
_writeString(text); // <----------------- string actual value
// And finally, closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"'; // <----------------- closing quote
}
To achieve what you want, there are at least two options:
1: Replace the quotes using Regex:
This is a safe approach because Jackson gives the double quotes (") already escaped (\"). All you have to do is escape the single quotes and switch the " around properties names and values:
ObjectMapper objectMapper = new ObjectMapper();
String str = objectMapper.writeValueAsString(model);
System.out.println("Received.: "+str);
str = str.replaceAll("'", "\\\\'"); // escapes all ' (turns all ' into \')
str = str.replaceAll("(?<!\\\\)\"", "'"); // turns all "bla" into 'bla'
System.out.println("Converted: "+str);
Output:
Received.: {"x":"ab\"c","y":"x\"y'z","z":15,"b":true}
Converted: {'x':'ab\"c','y':'x\"y\'z','z':15,'b':true}
Or 2: User a custom JsonSerializer on every String field
Declare the custom serializer:
public class SingleQuoteStringSerializer extends JsonSerializer<String> {
#Override
public void serialize(String str, JsonGenerator jGen, SerializerProvider sP)
throws IOException, JsonProcessingException {
str = str.replace("'", "\\'"); // turns all ' into \'
jGen.writeRawValue("'" + str + "'"); // write surrounded by single quote
}
}
Use it in the fields you want to single quote:
public class MyModel {
#JsonSerialize(using = SingleQuoteStringSerializer.class)
private String x;
...
And proceed as usual (QUOTE_FIELD_NAMES == false is used to unquote the field names):
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
String str = objectMapper.writeValueAsString(model);
System.out.println("Received.: "+str);
Output:
Received.: {x:'ab"c',y:'x"y\'z',z:15,b:true}
Note: Since you seem to be wanting to embed the JSON into another, this last approach may also require escaping the "s (see x:'ab"c').
Configure ObjectMapper in the following way:
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//this may be what you need
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
Try looking into gson. It would look like this in gson.
House myHouse = new House();
Gson gson = new Gson();
String json = gson.toJson(myHouse);
Done...
http://code.google.com/p/google-gson/
As I said in the comment that's not valid JSON and it doesn't make any sense to escape it. You should handle it in a different way.
You should put that object inside a property.
I think you want to have something like
{"myString":"{\"fake json\":\"foo\"}"}
instead you should have:
{"myString":{"fake json":"foo"}}
That should be the proper way to handle this.
Related
I want to convert each integer/double value to String present in json request before storing in MongoDB database.
There can be multiple fields like amountValue in the json. I am looking for a generic way which can parse json with any number of such attributes value to string. My request will have around 200 fields.
ex: "amountValue": 200.00, to "amountValue": "200.00",
{
"templateName": "My DC Template 14",
"templateDetails": {
"beneficiaryName": "Snow2",
"dcOpenAmount": {
"amountValue": 200.00,
}
}
}
My mongoDB Document is of the form
#Document
public class TemplateDetails {
#Id
private long templateId;
private String templateName;
private Object templateDetail;
}
Because we are storing document in mongodb as an object(Which can accept any type of json request) we dont have field level control on it.
In my controller, converting the request object to json.
This is how I tried. But its not meeting my expectation. It is still keeping the amount value to its original double form.:
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writeValueAsString(templateRequestVO);
System.out.println("ResultingJSONstring = " + json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
Output :
ResultingJSONstring = {"id":null,"userId":"FU.ZONKO","txnType":"LCI","accessIndicator":"Public","templateId":null,"templateName":"My DC Template 14","tags":null,"templateDetails":{"applicantDetail":{"applicantName":"Tom","applicantAddress":{"addressLine1":"Infosys, Phase 2","city":"PUNE","state":"MAHARASHTRA","country":"INDIA","zip":"40039"},"accountId":"Account1234","customerId":"JPMORGAN"},"beneficiaryName":"Snow2","dcOpenAmount":{"amountValue":200.0,"currency":"USD"}}}
Is there any way to accomplish the result ? Or anything which can help to store documents in mongodb with attribute type as String ?
You can use Json manipulation avaliable in "org.json.JSONObject" to convert Double value to Stirng .
If your Json structure won't change and will remain as said above , you can do the following.
import org.json.JSONObject;
public static void main(String args[]) {
String j = "{ \"templateName\": \"My DC Template 14\", \"templateDetails\": { \"beneficiaryName\": \"Snow2\", \"dcOpenAmount\": { \"amountValue\": 200.00 } } }";
JSONObject jo = new JSONObject(j);
jo.getJSONObject("templateDetails")
.getJSONObject("dcOpenAmount")
.put("amountValue", String.valueOf(jo.getJSONObject("templateDetails").getJSONObject("dcOpenAmount").getDouble("amountValue")));
System.out.println(jo.toString());
}
Following will be the output
{"templateDetails":{"dcOpenAmount":{"amountValue":"200.0"},"beneficiaryName":"Snow2"},"templateName":"My DC Template 14"}
I don't know for mongodb but for a json string you can replace them with a regex and the function replace like this :
public class Test {
public static void main(String[] args) {
String json = "{\"id\":null,\"userId\":\"FU.ZONKO\",\"txnType\":\"LCI\",\"accessIndicator\":\"Public\",\"templateId\":null,\"templateName\":\"My DC Template 14\",\"tags\":null,\"templateDetails\":{\"applicantDetail\":{\"applicantName\":\"Tom\",\"applicantAddress\":{\"addressLine1\":\"Infosys, Phase 2\",\"city\":\"PUNE\",\"state\":\"MAHARASHTRA\",\"country\":\"INDIA\",\"zip\":\"40039\"},\"accountId\":\"Account1234\",\"customerId\":\"JPMORGAN\"},\"beneficiaryName\":\"Snow2\",\"dcOpenAmount\":{\"amountValue\":200.0,\"currency\":\"USD\"}}}";
System.out.println(replaceNumberByStrings(json));
}
public static String replaceNumberByStrings(String str){
return str.replaceAll("(?<=:)\\d+(\\.\\d+)?(?=(,|}))","\"$0\"");
}
}
It will look for all fields with a numeric value in the json string and add quotes to the value. This way they will be interpreted as strings when the json willl be parsed.
It will not work if the value is in an array though, but in this case it should not be a problem.
Here is how I am trying to convert an object to json String
ObjectNode batch = OBJECT_MAPPER.createObjectNode();
String s = OBJECT_MAPPER.writeValueAsString((triggerCommands.getCommands()));
batch.put("commands", s);
System.out.println("raw String= " + s);
System.out.println("ObjectNode String = " + batch);
Which results in output of;
raw String= [{"cmdid":"a06c00d4-5b8b-4313-a8f3-5663dde0fa5b","type":"test"}]
ObjectNode String = {"commands":"[{\"cmdid\":\"a06c00d4-5b8b-4313-a8f3-5663dde0fa5b\",\"type\":\"test\"}]"}
I am curious to know why the String gets backslash when I add it into as value of ObjectNode. All i want is
ObjectNode String = {"commands":[{"cmdid":"a06c00d4-5b8b-4313-a8f3-5663dde0fa5b","type":"test"}]}
There is a similar question asked here but has no solid answer that worked.
Since you're working in the JsonNode domain, you want Jackson to convert your commands to a JsonNode, not a String. Like this:
ObjectNode batch = OBJECT_MAPPER.createObjectNode();
JsonNode commands = OBJECT_MAPPER.valueToTree(triggerCommands.getCommands());
batch.set("commands", commands);
I just read some sourcecodes toString() method of ObjectNode class, calls a TextNode.appendQuoted then a static method CharTypes.appendQuoted(StringBuilder sb, String content), this adds the ( " ) when the object is writed by toString(), here.. when is found a char " then it adds a backlash.
Since your key(s) is a Object array, if you check ObjectNode.put implementation its doesn't allow you add a key as array so.. it need to be parsed to a String
Note you wont get this.
ObjectNode String = {"commands":[{"cmdid":"a06c00d4-5b8b-4313-a8f3-5663dde0fa5b","type":"test"}]}
because the key it's not with between a " (quotes) and as a I told
ObjectNode doesn't allow you a key of type array.
private String writeUnicodeString() {
ObjectMapper mapper = new ObjectMapper();
ObjectNode node = mapper.getNodeFactory().objectNode();
node.put("field1", "Hello World");
return node.toString();
}
This outputs:
{"field1":"Hello World"}
I know I can reformat JSON objects in Java (using Jackson, GSON, etc.) to go from
{"a":"b", "c":"d"}
to
{
"a": "b",
"c": "d"
}
But how do I go convert a JSON object back to one-object-per-line format, i.e how do I get from
{
"a": "b",
"c": "d"
}
to
{"a":"b", "c":"d"}
in Java using an existing pretty-printer?
Take a look at the following URL:
Jackson Serialization features
This will show you how you can disable features, like indent output on a per call basis, even if you are reusing the same object that has been configured for pretty printing.
I think Pretty Print is a Jackson 1.x nomenclature though... and you should be looking for SerializationFeature.INDENT_OUTPUT
#Test
public void test() throws Exception {
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
String s = "{ \"a\" : \"b\" ,\n \"c\" : \"d\"}";
Object x = mapper.readValue(s, Object.class);
ObjectWriter w = mapper.writer();
// Indented
System.out.println(w.writeValueAsString(x));
// Single Line
System.out.println(w.without(SerializationFeature.INDENT_OUTPUT).writeValueAsString(x));
}
Since you are already using Jackson, it should work out of the box using:
String prettyJson = "{ \"a\" : \"b\" ,\n \"c\" : \"d\"}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode;
try {
jsonNode = objectMapper.readValue(prettyJson, JsonNode.class);
System.out.println(jsonNode.toString());
} catch (IOException e) {
e.printStackTrace();
}
I am reading JSON data from a file.
Sample Data
{"name":"user1","myparam0":false,"myparam1":"44750004-23df-4960-88be-ba0884291597","myparam2":"36A3BF29-23df-EE2A-76B9-19BC1C854BA7","myparam3":"http://www.seloger.com/","myparam4":"http://www.seloger.com/erreur-temporaire/husk-pie","ver":"4.0.0"}
{"name":"user1","myparam0":true,"myparam1":"44750004-8bff-4960-88be-ba0884291597","myparam2":"36A3BF29-88be-EE2A-76B9-19BC1C854BA7","myparam3":"","myparam4":"http://www.seloger.com/erreur-temporaire/binde","ver":"4.0.0"}
I have written a sample code to read from the file and converted data to JSON like this
DataStream<Object> input = env.readTextFile("file:///home/ravisankar/workspace/temporary/input.file")
.map((line) -> {
return JSON.parseFull(line);
});
Now I need to calculate how many myparam3 are empty in 15 seconds based on the name. and group by myparam4
Ex: {
"user1": {
"myparams3": 1,
"myparam4": {
"http://www.seloger.com/erreur-temporaire/binde": 1,
"http://www.seloger.com/erreur-temporaire/husk-pie": 1
}
}
}
Is it possible to extract such data like this from Flink?? I don't see any examples working on JSON using Java. Thanks for your time
You could parse your json string to object i.e. via jackson library and operate a stream of java objects as usual
you can use jackson to parse the json to an object then make a loop to count your elements
private ObjectMapper objectMapper = new ObjectMapper() ;
...
Object element = objectMapper.readValue( jsonString , Object.class );
or you can use a regex that matches "myparam3":"" and calculate tha matches
public static void main( String[] args ) throws IOException
{
String str = "{\"name\":\"user1\",\"myparam0\":false,\"myparam1\":\"44750004-23df-4960-88be-ba0884291597\",\"myparam2\":\"36A3BF29-23df-EE2A-76B9-19BC1C854BA7\",\"myparam3\":\"http://www.seloger.com/\",\"myparam4\":\"http://www.seloger.com/erreur-temporaire/husk-pie\",\"ver\":\"4.0.0\"}\r\n" +
"{\"name\":\"user1\",\"myparam0\":true,\"myparam1\":\"44750004-8bff-4960-88be-ba0884291597\",\"myparam2\":\"36A3BF29-88be-EE2A-76B9-19BC1C854BA7\",\"myparam3\":\"\",\"myparam3\":\"\",\"myparam3\":\"\"\"myparam4\":\"http://www.seloger.com/erreur-temporaire/binde\",\"ver\":\"4.0.0\"}";
Pattern pattern = Pattern.compile("\"myparam3\":\"\"");
Matcher matcher = pattern.matcher(str);
int count = 0;
while (matcher.find()) {
count++;
}
System.out.println("Matches found : " + count );
}
Is there a way to convert my output from ToStringBuilder back to java object?
I am looking for an easy way to represent a Java object in readable text file and being able to convert back and forth between string and object.
Thanks,
You must define a strict format and follow it with a parser. There are two accepted formats:
XML - you can use java.beans.XMLEncoder
JSON - use Jackson or gson
If you don't choose these formats you will have to handle the parsing yourself.
The ToStringBuilder does not seem to have a reverse equivalent. Furthermore it is wrong to use this string representation for such purposes - it is meant only for debug.
You'll have to parse your string representation of the object and then construct a new object initialised with those values.
If you want to keep it generic and have it work for any object type, you can use Apache BeanUtils to help.
For example, if your string representation is:
Person#7f54[name=Stephen,age=29,smoker=false]
Parse out the class name, fields and values. Then use BeanUtils to construct a new Person:
String className = "Person";
Class beanClass = Class.forName(className);
Person myPerson = (Person)beanClass.newInstance();
BeanUtils.setProperty(myPerson, "name", "Stephen");
BeanUtils.setProperty(myPerson, "age", "29");
BeanUtils.setProperty(myPerson, "smoker", "false");
This assumes that your Person class is a bean and exposes getters/setters for its fields.
Sean, I came across your question while looking for a simple test case converter based on a reflection-based String output of an object. While a more robust library for json or XML is certainly important for a wide range of input, this is handy for quick and dirty test cases. It handles simple, non-nested POJOs. Its only dependency is apache commons.
I'm using this toString format:
#Override
public String toString() {
return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
Here is the class:
public class FromStringBuilder {
/**
* Parses a string formatted with toStringBuilder
*
* #param input - ex. "Path[id=1039916,displayName=School Home,description=<null>,...]"
* #return hashmap of name value pairs - ex. id=1039916,...
*/
public static Map<String, String> stringToMap(String input) {
LinkedHashMap<String, String> ret = new LinkedHashMap<String, String>();
String partsString = StringUtils.substringBetween(input, "[", "]");
String[] parts = partsString.split(",");
for (String part:parts) {
String[] nv = part.split("=");
if (!StringUtils.equals("<null>", nv[1])) {
ret.put(nv[0], nv[1]);
}
}
return ret;
}
public static <T> T stringToObject(String input, Class<T> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
Map<String, String> map = stringToMap(input);
T ret = clazz.newInstance();
BeanUtils.copyProperties(ret, map);
return ret;
}
}
XStream library is the perfect one
Here is an example of using Gson:
public class GsonTest {
static class Name { String first; String last; }
static class Data { int number; Name name = new Name(); }
public static void main(String[] args) {
Gson gson = new Gson();
Data data1 = new Data();
data1.number = 1;
data1.name.first = "Joe";
data1.name.last = "Smith";
print("data1", data1);
String jsonString = gson.toJson(data1);
System.out.println("jsonString: " + jsonString);
Data data2 = gson.fromJson(jsonString, Data.class);
print("data2", data2);
}
private static void print(String id, Data data) {
System.out.println(id + " :"
+ " number=" + data.number
+ " name.first=" + data.name.first
+ " name.last=" + data.name.last);
}
}
Output
data1 : number=1 name.first=Joe name.last=Smith
jsonString: {"number":1,"name":{"first":"Joe","last":"Smith"}}
data2 : number=1 name.first=Joe name.last=Smith
Speed
Gson should be roughly as fast as any other comparable reflection-based Object<->Text serialization framework, but I do not have benchmark data.
Bean Support
Unlike XStream(optionally) and java.beans.XMLEncoder/XMLEncoder, Gson does not use a class's setter and getter methods. Rather it reads and writes the member fields of the class directly, similar to Java binary serialization (ObjectOutputStream, etc.) While Gson should be able to properly marshal and unmarshal most JavaBeans, this implementation detail of Gson must be kept in mind and accounted for.
Pretty-printed JSON Output
By default GSON outputs JSON all on one line, as an optimization. It can output JSON that is slightly easier to read. Do this by constructing the Gson object in a slightly different way:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
The JSON output (continuing the example above), now looks like:
{
"number": 1,
"name": {
"first": "Joe",
"last": "Smith"
}
}
instead of
{"number":1,"name":{"first":"Joe","last":"Smith"}}