I am trying to convert JSON to XML in middle ware tool. I am using Jackson libraries to do this transformation. The problem is that for decimal fields (length more than 8) in JSON, the corresponding XML value is converted to scientific notation. For example 8765431002.13 is converted to 8.76543100213E8.
I can convert the scientific notation to normal decimal format if know the name of the field. But in my case, the middleware application will not be aware of field that is coming as decimal.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class JSONDataformat {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//String jsonString = "{\"Field1\":18629920.68,\"Field3\":\"test\", \"Field2\":\"null\"}";
ObjectMapper objectMapper = new ObjectMapper();
ObjectMapper xmlMapper = new XmlMapper();
JsonNode tree = objectMapper.readTree(jsonString);
String jsonAsXml = xmlMapper.writer().writeValueAsString(tree);
System.out.println(jsonAsXml);
}
catch(Exception e) {e.printStackTrace(); }
}
}
Output
<ObjectNode xmlns=""><Field1>1.862992068E7</Field1><Field3>test</Field3><Field2/></ObjectNode>
I expected to get <Field1> value as 18629920.68 in above code.
You need to enable USE_BIG_DECIMAL_FOR_FLOATS feature:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
EDIT
import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
String jsonString = "{\"Field1\": 20121220.00,\"Field3\":\"test\", \"Field2\":\"null\"}";
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
XmlMapper xmlMapper = new XmlMapper();
JsonNode tree = jsonMapper.readTree(jsonString);
String jsonAsXml = xmlMapper.writer().with(Feature.WRITE_BIGDECIMAL_AS_PLAIN).writeValueAsString(tree);
System.out.println(jsonAsXml);
}
}
Above code prints:
<ObjectNode><Field1>20121220</Field1><Field3>test</Field3><Field2>null</Field2></ObjectNode>
Related
I try to convert a JSON into an XML with the following code
final ObjectMapper objectMapper = new ObjectMapper();
final XmlMapper xmlMapper = new XmlMapper();
JsonNode jsonNode = objectMapper.readTree(jsonString);
String xmlString = xmlMapper
.writerWithDefaultPrettyPrinter()
.withRootName("rootname")
.writeValueAsString(jsonNode);
Basically it works. Does anyone know, how I can add a namespace to the serialized XML-attributes. I've no POJOs for the objects. The convert should generate from this
{
"Status" : "OK"
}
something like this:
<ns2:rootname xmlns:ns2="http://whatever-it-is.de/">
<ns2:state>OK</ns2:state>
</ns2:rootname>
just create a pojo and add jackson annotations, e.g.
#JacksonXmlProperty(localName="ns2:http://whatever-it-is.de/")
public class Status {
// ...
}
Or if you want to go without a pojo try a custom serializer which adds namespaces
https://www.baeldung.com/jackson-custom-serialization
You need to provide custom Json Node serialiser and use ToXmlGenerator. See below example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.IOException;
public class XmlMapperApp {
public static void main(String... args) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
ObjectNode node = xmlMapper.createObjectNode()
.put("Status", "OK")
.set("node", xmlMapper.createObjectNode()
.put("int", 1)
.put("str", "str"));
SimpleModule module = new SimpleModule();
module.setSerializerModifier(new BeanSerializerModifier() {
#Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getType().getRawClass().equals(ObjectNode.class)) {
return new ObjectNodeJsonSerializer(serializer);
}
return super.modifySerializer(config, beanDesc, serializer);
}
});
xmlMapper.registerModule(module);
System.out.println(xmlMapper.writeValueAsString(node));
}
}
class ObjectNodeJsonSerializer extends JsonSerializer<JsonNode> {
private final JsonSerializer baseSerializer;
ObjectNodeJsonSerializer(JsonSerializer baseSerializer) {
this.baseSerializer = baseSerializer;
}
#Override
public void serialize(JsonNode value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGenerator = (ToXmlGenerator) gen;
xmlGenerator.setNextName(new QName("http://whatever-it-is.de/", "rootname", "anything"));
baseSerializer.serialize(value, gen, serializers);
}
}
Above example prints:
<wstxns1:rootname xmlns:wstxns1="http://whatever-it-is.de/">
<wstxns1:Status>OK</wstxns1:Status>
<wstxns1:node>
<wstxns1:int>1</wstxns1:int>
<wstxns1:str>str</wstxns1:str>
</wstxns1:node>
</wstxns1:rootname>
Underscore-java library can convert JSON to XML with namespace.
{
"ns2:rootname": {
"-xmlns:ns2": "http://whatever-it-is.de/",
"ns2:state": "OK"
},
"#omit-xml-declaration": "yes"
}
<ns2:rootname xmlns:ns2="http://whatever-it-is.de/">
<ns2:state>OK</ns2:state>
</ns2:rootname>
I'm writing the below to convert CSV file to JSON but getting java heap memory error.
Can anyone help me to write using the Jackson stream API?
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
File input = new File("C:\\Users\\shivamurthym\\Downloads\\FL_insurance_sample\\FL_insurance_sample.csv");
File output = new File("C:\\Users\\shivamurthym\\data.json");
List<Map<?, ?>> data = readObjectsFromCsv(input);
writeAsJson(data, output);
}
public static List<Map<?, ?>> readObjectsFromCsv(File file) throws IOException {
CsvSchema bootstrap = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<Map<?, ?>> mappingIterator = csvMapper.reader(Map.class).with(bootstrap).readValues(file);
return mappingIterator.readAll();
}
public static void writeAsJson(List<Map<?, ?>> data, File file) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(file, data);
}
}
I wrote the following JsonSerializer to let Jackson serialize an array of integers into JSON:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class TalkIdsSerializer extends JsonSerializer<TalkIds> {
/**
* Serializes a TalkIds object into the following JSON string:
* Example: { "talk_ids" : [ 5931, 5930 ] }
*/
#Override
public void serialize(TalkIds talkIds, JsonGenerator jsonGenerator,
SerializerProvider provider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeArrayFieldStart(TalkIds.API_DICTIONARY_KEY);
for (Integer talkId : talkIds.getTalkIds()) {
jsonGenerator.writeNumber(talkId);
}
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
}
}
The class is used here:
#JsonSerialize(using = TalkIdsSerializer.class)
public class TalkIds { /* ... */ }
I want test the behavior of the serializer and came up with the following:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class TalkIdsSerializerTest {
protected final ArrayList<Integer> TALK_IDS =
new ArrayList<>(Arrays.asList(5931, 5930));
protected TalkIdsSerializer talkIdsSerializer;
#Before
public void setup() throws IOException {
talkIdsSerializer = new TalkIdsSerializer();
}
#Test
public void testSerialize() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonGenerator jsonGenerator =
new JsonFactory().createGenerator(stringWriter);
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
talkIdsSerializer.serialize(talkIds, jsonGenerator, null);
String string = stringWriter.toString(); // string is ""
assertNotNull(string);
assertTrue(string.length() > 0);
stringWriter.close();
}
}
However, nothing is written to the StringWriter. What am I doing wrong?
You need to flush() the generator
Method called to flush any buffered content to the underlying target (output stream, writer), and to flush the target itself as well.
http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/core/JsonGenerator.html#flush()
I had a similar requirement, to test a custom serializer. I used objectMapper to get the string directly(since you have already annotated TalkIds with JsonSerialize). You can get the json string from the object as follows
String json = new ObjectMapper().writeValueAsString(talkIds)
For me flush() changed nothing, so I changed the way to test it, in accordance with http://www.baeldung.com/jackson-custom-serialization.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.StringWriter;
//...
#Test
public void serialize_custom() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(MyCustomSerializer.class, myCustomSerializer);
objectMapper.registerModule(module);
StringWriter stringWriter = new StringWriter();
TalkIds talkIds = new TalkIds();
talkIds.add(TALK_IDS);
objectMapper.writeValue(stringWriter,wi);
assertTrue(stringWriter.toString().length() > 3);
}
I am using Jackson objectMapper to read JSON to JsonNode, Then I am using xmlMapper to serialize this to XML.
I'd like to set an XML attribute value by parsing a JSON attribute with tag "#". Any help would be appreciated. Thanks.
EXAMPLE JSON:
{
"response" : {
"label" : {
"#data" : "someValue"
}
}
}
NEED TO MAP TO XML:
<response>
<label data="someValue" />
</response>
This is what I can get right now:
<response>
<label>
<#data>someValue</#data>
</label>
</response>
CODE:
JsonNode root = objectMapper.readTree(JSON);
xml = xmlMapper.writeValueAsString(root);
well, I found a solution that produces the required output. However, I am not sure if this is an optimal solution, in a sense that it requires custom inner classes to be able to specify the annotations that tell the mappers how to parse.
import java.util.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public class JSONTest
{
#SuppressWarnings("unchecked")
public static void main(String[] args)
{
try {
String jsonInput = "{ \"response\" : { \"label\" : { \"#data\" : \"someValue\" } }}";
ObjectMapper om = new ObjectMapper();
TypeFactory tf = om.getTypeFactory();
JavaType mapType = tf.constructMapType(HashMap.class, String.class, response.class);
Map<String, response> map = (Map<String, response>)om.readValue(jsonInput, mapType);
XmlMapper xmlMapper = new XmlMapper();
String ss = xmlMapper.writeValueAsString(map.get("response"));
System.out.println(ss);
} catch (Exception e) {
e.printStackTrace();
}
}
public static class response {
public Label label;
}
public static class Label {
#JsonProperty("#data")
#JacksonXmlProperty(isAttribute = true)
public String data;
}
}
output:
<response><label data="someValue"/></response>
I am using following code:
CsvSchema bootstrap = CsvSchema.emptySchema().withHeader();
ObjectMapper mapper = new CsvMapper();
File csvFile = new File("input.csv"); // or from String, URL etc
Object user = mapper.reader(?).withSchema(bootstrap).readValue(new File("data.csv"));
mapper.writeValue(new File("data.json"), user);
It throws an error in my IDE saying cannot find symbol method withSchema(CsvSchema) but why? I have used the code from some examples.
I don't know what to write into mapper.reader() as I want to convert any CSV file.
How can I convert any CSV file to JSON and save it to the disk?
What to do next? The examples
I think, you should use MappingIterator to solve your problem. See below example:
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
File input = new File("/x/data.csv");
File output = new File("/x/data.json");
List<Map<?, ?>> data = readObjectsFromCsv(input);
writeAsJson(data, output);
}
public static List<Map<?, ?>> readObjectsFromCsv(File file) throws IOException {
CsvSchema bootstrap = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
try (MappingIterator<Map<?, ?>> mappingIterator = csvMapper.readerFor(Map.class).with(bootstrap).readValues(file)) {
return mappingIterator.readAll();
}
}
public static void writeAsJson(List<Map<?, ?>> data, File file) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(file, data);
}
}
See this page: jackson-dataformat-csv for more information and examples.