SerializationFeature.INDENT_OUTPUT ignored on Jackson 2.6.5 - java

I'm using Jackson mapper version 2.6.5 with Spring Boot but I can seem to get SerializationFeature.INDENT_OUTPUT to work. I'm following the tutorial here. My code is as follows.
public class SerializationExampleTreeModel {
public static void main(String[] args) throws IOException {
// Create the node factory that gives us nodes.
JsonNodeFactory nodeFactory = new JsonNodeFactory(false);
StringWriter stringWriter = new StringWriter();
// create a json factory to write the treenode as json. for the example
// we just write to console
JsonFactory jsonFactory = new JsonFactory();
JsonGenerator generator = jsonFactory.createGenerator(stringWriter);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
// the root node - album
JsonNode album = nodeFactory.objectNode();
album.put("Album-Title", "Kind Of Blue")
ArrayNode songs = nodeFactory.arrayNode()
songs.add("Song8").add("Song2")
album.put("Songs", songs)
ObjectNode artist = nodeFactory.objectNode()
artist.put("Name", "Alex" )
album.put( "artist", artist)
mapper.writeTree(generator, album)
println stringWriter.toString()
}
}
I always get the result:
{"Album-Title":"Kind Of Blue","Songs":["Song8","Song2"],"artist":{"Name":"Alex"}} whether I include the line mapper.configure(SerializationFeature.INDENT_OUTPUT, true) or not. What is going on?
Note: I'm compiling my code using groovyc and semi-colons aren't required.

The problem is you are using StringWriter to write the output and it ignores the formatting you set on ObjectMapper as expected. Instead, use:
System.out.println(mapper.writeValueAsString(album));
If you prefer to use as you are using, you can declare the printer like this before writing the tree:
generator.setPrettyPrinter(new DefaultPrettyPrinter());
mapper.writeTree(generator, album);
This will allow the correct output with:
stringWriter.toString()

Related

How to get custom schema draft in json-schema-validator-1.0.68.jar?

i am defining my custom schema draft in my json-schema.
{ "$schema": "http://oag.company.com/ver1/schema#",
"title": "JSON Identity Attribute Schema"
}
and want to fetch it in code validation.
i am using json-schema-validator-1.0.68.jar which comes with com.networknt.
my code
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
JsonSchemaFactory schemaFactory = JsonSchemaFactory.getInstance();
String exppath="exp.json";
String schpath ="schm.json";
try (
InputStream jsonStream = new FileInputStream(exppath);
InputStream schemaStream = new FileInputStream(schpath);
) {
JsonNode json = objectMapper.readTree(jsonStream);
com.networknt.schema.JsonSchema schema = schemaFactory.getSchema(schemaStream);
Set<ValidationMessage> validationResult = schema.validate(json);
if (validationResult.isEmpty()) {
System.out.println("no validation errors :-)");
System.out.println(json.path("FirstName"));
} else {
validationResult.forEach(vm -> System.out.println(vm));
}
}
}
the error message i got is
Exception in thread "main" com.networknt.schema.JsonSchemaException: Unknown MetaSchema: https://oag.oracle.com/ver1/schema
is thier any way so i can use my custom schema or can i use any other library which allow custom schema ?

How to modify content of json file?

is there any option to modify content of json file? I have 2 methods, export to json file list of different objects, and import from file.
public static void exportShapeListToJson(List<Shape> list, String path) throws IOException {
ObjectMapper mapper = new ObjectMapper();
File file = new File(path);
mapper.enableDefaultTyping();
mapper.writeValue(new File(file.getName()), list);
}
public static List<Shape> importFromJson(String path) throws IOException {
File file = new File(path);
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
return mapper.readValue(file, ArrayList.class);
}
Saved data in file looks like:
["Project1.shapeService.models.Circle",{"radius":3.0}],["Project1.shapeService.models.Circle",{"radius":5.0}],["Project1.shapeService.models.Rectangle",{"a":1.0,"b":2.0}]
Can i modify that data to form like that:
[{"type": "squre", "a": 10}, {"type": "circle", "r": 10}]
and still use method to import? What have to add/ change?

write jackson objectNode without escape characters

I wanted to remove escape characters while writing string. My code is as below.
private static ObjectMapper objectMapper = new ObjectMapper();
public static JsonNode MyMethod()
{
InputStream cleanUp = TestHelper.class.getClassLoader().getResourceAsStream("file.txt");
message = new String(cleanUp.readAllBytes());
objectMapper.getFactory().configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(),false);
root = objectMapper.readTree(new File("filePath"));
((ObjectNode) root).put("message", message );
return root;
}
Contain of the file.txt
[{\n \"timestamp\": 1599456392538
Expected :
"[{\n \"timestamp\": 1599456392538"
Actual :
"[{\\n \\\"timestamp\\\": 1599456392538"

How to use jackson in Java if a json can represent 2 classes?

I'm using Jackson to deserialize objects in Java, e.g. here's one of hello world examples:
Foo foo = new ObjectMapper().readValue(jsonFoo, Foo.class);
There's a problem with my json string, though: it may be either
{
"error":{
"code":"404",
"message":"Not Found"
}
}
or
[{fooFields}, {fooFields}]
So usually for the latter case, I would use:
Foo[] foos = new ObjectMapper().readValue(jsonFoo, []Foo.class);
or
Error error = new ObjectMapper().readValue(jsonFoo, Error.class);
How can I try to parse jsonFoo to either Error or [Foo] and return another custom Error object if there's an exception?
Currently, I only managed to come up with a nested try-catch construction which doesn't look really nice.
try {
Foo[] foos = new ObjectMapper().readValue(jsonFoo, []Foo.class);
return new Bar(foos);
catch {
try {
Error error = new ObjectMapper().readValue(jsonFoo, Error.class);
return new Bar(error);
catch (IOException e)... // new Bar(InvalidInputError);
}
return new Bar(InvalidInputError);
Is there a way to rewrite it in a more concise way?
I usually use JsonNode.
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr1 = "[{\"key\":\"value\"}]";
JsonNode jsonNode1 = objectMapper.readTree(jsonStr1);
boolean array = jsonNode1.isArray();
String jsonStr2 = "{\"key\":\"value\"}";
JsonNode jsonNode2 = objectMapper.readTree(jsonStr2);
boolean object = jsonNode2.isObject();
}
More information

how can i unmarshall in jaxb and enjoy the schema validation without using an explicit schema file

I am using jaxb for my application configurations
I feel like I am doing something really crooked and I am looking for a way to not need an actual file or this transaction.
As you can see in code I:
1.create a schema into a file from my JaxbContext (from my class annotation actually)
2.set this schema file in order to allow true validation when I unmarshal
JAXBContext context = JAXBContext.newInstance(clazz);
Schema mySchema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaFile);
jaxbContext.generateSchema(new MySchemaOutputResolver()); // ultimately creates schemaFile
Unmarshaller u = m_context.createUnmarshaller();
u.setSchema(mySchema);
u.unmarshal(...);
do any of you know how I can validate jaxb without needing to create a schema file that sits in my computer?
Do I need to create a schema for validation, it looks redundant when I get it by JaxbContect.generateSchema ?
How do you do this?
Regarding ekeren's solution above, it's not a good idea to use PipedOutputStream/PipedInputStream in a single thread, lest you overflow the buffer and cause a deadlock. ByteArrayOutputStream/ByteArrayInputStream works, but if your JAXB classes generate multiple schemas (in different namespaces) you need multiple StreamSources.
I ended up with this:
JAXBContext jc = JAXBContext.newInstance(Something.class);
final List<ByteArrayOutputStream> outs = new ArrayList<ByteArrayOutputStream>();
jc.generateSchema(new SchemaOutputResolver(){
#Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
outs.add(out);
StreamResult streamResult = new StreamResult(out);
streamResult.setSystemId("");
return streamResult;
}});
StreamSource[] sources = new StreamSource[outs.size()];
for (int i=0; i<outs.size(); i++) {
ByteArrayOutputStream out = outs.get(i);
// to examine schema: System.out.append(new String(out.toByteArray()));
sources[i] = new StreamSource(new ByteArrayInputStream(out.toByteArray()),"");
}
SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
m.setSchema(sf.newSchema(sources));
m.marshal(docs, new DefaultHandler()); // performs the schema validation
I had the exact issue and found a solution in the Apache Axis 2 source code:
protected List<DOMResult> generateJaxbSchemas(JAXBContext context) throws IOException {
final List<DOMResult> results = new ArrayList<DOMResult>();
context.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String ns, String file) throws IOException {
DOMResult result = new DOMResult();
result.setSystemId(file);
results.add(result);
return result;
}
});
return results;
}
and after you've acquired your list of DOMResults that represent the schemas, you will need to transform them into DOMSource objects before you can feed them into a schema generator. This second step might look something like this:
Unmarshaller u = myJAXBContext.createUnmarshaller();
List<DOMSource> dsList = new ArrayList<DOMSource>();
for(DOMResult domresult : myDomList){
dsList.add(new DOMSource(domresult.getNode()));
}
String schemaLang = "http://www.w3.org/2001/XMLSchema";
SchemaFactory sFactory = SchemaFactory.newInstance(schemaLang);
Schema schema = sFactory.newSchema((DOMSource[]) dsList.toArray(new DOMSource[0]));
u.setSchema(schema);
I believe you just need to set a ValidationEventHandler on your unmarshaller. Something like this:
public class JAXBValidator extends ValidationEventCollector {
#Override
public boolean handleEvent(ValidationEvent event) {
if (event.getSeverity() == event.ERROR ||
event.getSeverity() == event.FATAL_ERROR)
{
ValidationEventLocator locator = event.getLocator();
// change RuntimeException to something more appropriate
throw new RuntimeException("XML Validation Exception: " +
event.getMessage() + " at row: " + locator.getLineNumber() +
" column: " + locator.getColumnNumber());
}
return true;
}
}
And in your code:
Unmarshaller u = m_context.createUnmarshaller();
u.setEventHandler(new JAXBValidator());
u.unmarshal(...);
If you use maven using jaxb2-maven-plugin can help you. It generates schemas in generate-resources phase.

Categories