I have a complex model class in Java that has attributes of different class. I wanted to get the schema of the class in yml format for better readability. I was able get the structure of the class to a JSON file but I feel that yml is less cluttered and easy to ready.
Example
From
public class Phone {
public String name;
public String number;
}
To
Phone:
fields:
name:
type: String
number:
type: String
The Jackson library offers the ability to generate a JSONSchema from a Java class. You should be able to serialize it into a YAML, although I haven't actually tested this part. Here how it might look like :
ObjectMapper m = new ObjectMapper();
SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
m.acceptJsonFormatVisitor(m.constructType(Phone.class), visitor);
JsonSchema jsonSchema = visitor.finalSchema();
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
mapper.writeValue(yamlFile, jsonSchema);
You may need this configuration if you use enums
mapper.configure(SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true);
More details at the github page of the Yaml module and the JSON schema module
From RAM to File
If your use case is to just serialize your existing objects, without reading them first, you might try the approach from this answer using Jackson; it just writes to a file an example object.
// Create an ObjectMapper mapper for YAML
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
// Write object as YAML file
mapper.writeValue(new File("/path/to/yaml/file"), example);
You can try http://jyaml.sourceforge.net/
The project is no longer active though.
An other approach may be the read the class files using the ASM library. It has a nice visitor API which lets you fairly simply transform the bytecode into an other representation like YAML (start here: http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassVisitor.html ). But it might be an overkill for your task.
Related
I am using Json type for my data, and i need a json schema to make a better description.
Can a sample Java code provide json schema?
I want a sample example.
Generally data model ( Java POJOs ) for the JSON is shared between data transferring parties.
But if you really want, then "jackson" can be used, example below converts a Java class to JSON Schema. You can furthe play around or look for similar libraries, tio suit your requirement.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
private String getJsonSchema(Class clazz) throws IOException
{
ObjectMapper mapper = new ObjectMapper();
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
com.fasterxml.jackson.module.jsonSchema.JsonSchema schema = schemaGen.generateSchema(clazz);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
}
I want to parse configuration yaml file as a JSON Object in Dropwizard.
As in Python and Ruby we can directly read yaml file as JSON:
require 'yaml'
conf = YAML.load_file('some.yml')
puts conf.<some key>
I want to follow the same protocol and do not want to make a separate class to map the yaml structure, but not sure how to achieve it in Java.
If I understand correctly, instead of defining a class to represent the structure of you JSON or YAML, you want to retrieve an object that gives you access to the JSON object in a generic manner.
Even though this is a bit contrary to the way dropwizard wants to do things (i.e., having typed class to access configuration data), it is relatively easy:
You need an instance of Jackson ObjectMapper: the one provided by dropwizard or you own, YAML-aware (see example below).
You can call the readTree method to transform an input into a JsonNode which gives you access to the JSON/YAML object in memory.
See ObjectMapper#readTree and similar methods.
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
JsonNode json = mapper.readTree(new File("some.yml"));
System.out.println(json.get("test"));
You can just use the Configuration object from DropWizard, either the default or a custom one that has been created to hold additional parameters. This object is available on the Application class, under the "run" method in particular. Using the DW configuration example:
public class ExampleConfiguration extends Configuration {
#Valid
#NotNull
private MessageQueueFactory messageQueue = new MessageQueueFactory();
#JsonProperty("messageQueue")
public MessageQueueFactory getMessageQueueFactory() {
return messageQueue;
}
#JsonProperty("messageQueue")
public void setMessageQueueFactory(MessageQueueFactory factory) {
this.messageQueue = factory;
}
}
You can get/set all the attributes from YAML file as below:
public class MyApplication extends Application<ExampleConfiguration> {
...
public void run(ExampleConfiguration configuration, Environment environment) {
configuration.getMessageQueueFactory();
configuration.getServerFactory();
}
}
Jackson can both parse yaml and format to JSON.
See an example here.
We are using Jackson to read json from the filesystem and parse it to the POJO.
POJO
String name;
Map<String,Object> map;
getters/setters
Reading
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
Pojo obj = mapper.readValue(jsonFile, Pojo.class);
Problem
When we have numbers in json (map part) they gets converted to Integer Or Double.And we want all our numbers (decimal and whole) as Type BigDecimal So I tried using the
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
But this only works for the decimal numbers. There is no feature available to covert whole numbers to BigDecimal.
Question
Do we have any inbuilt feature to enable ObjectMapper to read all the number to BigDecimal?
If I need to write custom serializer, Do I need to write it for the whole class or it can be written for Map field ?
You can register a Module with your ObjectMapper that includes a custom JsonDeserializer. You don't need to make your own because Jackson Databind provides a BigDecimalDeserializer but you need to do one more thing to make it work.
Because BigDecimalDeserializer is annotated with #JacksonStdImpl, Jackson won't allow you to use this directly because the initialization code (I currently disagree with this) specifically checks for this annotation and disallows it. Because this deserializer is not a final, you can get around this without copy-pasting by creating an anonymous subclass.
In the end, it will look something like this
Module module = new SimpleModule();
module.addDeserializer(Number.class, new NumberDeserializers.BigDecimalDeserializer() {});
new ObjectMapper().registerModule(module).readValue("{}", Map.class);
Try putting :BigDecimal:[dps] is in your json. For example :
{
"MY_BIG_D:BigDecimal:0" : 3
}
where dps = decimal places.
What is the way to generate a Java object with get and set methods?
You should write a java bean with properties maching the JSON key's, from that point since you already have a reader its a simple as
YourObject obj = gson.fromJson(br, YourObject.class);
UPDATE
With respect to your comment, when you don't want or can't create a bean it usually boils down to parsing JSON to map. GSON (afaik) doesn't have a built-in for this, but its not hard to build a method that will traverse GSON's objects. You have an example in this blog
http://itsmyviewofthings.blogspot.it/2013/04/jsonconverter-code-that-converts-json.html
As you seem to be open to alternatives, take a look at Jackson as well (the two libs are the de-facto standard in JAVA).
With jackson you don't have to create a bean to support deserialization, e.g.
String json = "{\"id\":\"masterslave\"}";
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();
//convert JSON string to Map
map = mapper.readValue(json,
new TypeReference<HashMap<String,String>>(){});
http://www.jsonschema2pojo.org/
That link helps generate the Java object format based on the GSON you feed in. Just make sure you set the settings exactly as you need it. As always, it's not a good idea to just copy-paste generated code, but it might be of help.
I'm in need of a JSON - > Pojo - > JSON transformation.
I looked into the mainstream libraries Jackson and GSON,
Apparently both use:
//write converted json data to a file named "file.json"
FileWriter writer = new FileWriter("c:\\file.json");
or In\Output Streams..
Two things scare me the most when i write new code:
I\O (HD specifically)
Serialization
I try to avoid both of these as much as I can.
Is there any alternative way to do this?
Those libraries DO NOT need to use files to operate, so answering your question: NO, file serialization is not mandatory. In fact it's not only not mandatory, but it'd be such a pain in the ass to read/write from/to a file each time you need to serialize/deserialize a JSON reponse!
In your example they use a File to write and read the JSON in order to imitate the usual scenario, which probably includes pass data from/to a web service for example, instead of from/to a File...
In fact, for example in Gson, serialization/deserialization is quite straightforward with a simple Pojo, just like this:
Serialization
Pojo pojo = new Pojo();
Gson gson = new Gson();
String pojoJSON = gson.toJson(pojo);
Deserialization
Gson gson = new Gson();
Pojo pojo = gson.fromJson(pojoJSON, Pojo.class);
I suggest you to take a look at Gson documentation, which is pretty clear and quite short, once you read it you'll understand everything much better...