I have an interesting problem in with one of my projects.
I have ZipInputeStream from uploaded zip in spring boot application with several yaml file in it, which can have any name and dynamic content which we know and have java POJO objects for them.
For e.g. Below yaml corresponds to BaseModel.java
---
baseModel:
other contents
class BaseModel{}
and below yaml will correspond to TopModel.java
---
topModel:
other contents
class TopModel{}
Now the Question is how do i decide which java class to use for object creation at runtime based on the yaml file string.
I am using jackson and tried converting yaml string to JSON but that requires a type in JSON which we dont have in the file and we cant get it added as well.
Any help on this would really be appreciated.
Thanks.
Related
I am getting a config.xml file via a REST API which has a specific structure. I am adapting this config.xml via Java and pushing it again via PUT command to the REST endpoint to update it.
This XML structure contains the same amount of properties (let's say 'name' and 'description') but might be enhanced by some more properties (e.g. 'category'), which I am not aware of.
<config>
<name>myName</name>
<description>myDescription<description>
<category>myCategory<category>
</config>
My goal is to adapt this config file via Java Code while wrapping it into an Object. So I built a Class 'Config' containing 'String name' and 'String description'.
I can easily parse the config.xml to my Config object with JAXB and adapt name and description, but when marshalling it to XML the category would be missing, although it was returned by the REST API. Is there a way (maybe ValueChangeListener?) to adapt only the changed values in an existing xml file?
public class Config { String name; String description; }
So I don't event want to be able to change 'category' at all, I just don't want to lose the data.
Info: In my scenario the Config class is very complex and has alot of subclasses (it's a representing a Jenkins Job). So the example above is very simplified.
I got the idea to create a second config file, only having the changed parameters. Afterwards merging the to config files. But I had no idea how to be aware what exactly has changed and how to implement it.
Example:
I want to change description to "newDescription", so my expected XML would be:
<config>
<name>myName</name>
<description>newDescription<description>
<category>myCategory<category>
</config>
unfortuntately it is:
<config>
<name>myName</name>
<description>newDescription<description>
</config>
Means category parameter is lost, as I am not aware of it and therefore didnt add it to the Config class. Summarized, there might be parameters in the XML file which I am not aware, which I also do not want to change - but don't want to lose when pushing an updated config.
I used to work with the Java framework spring boot which has this neat functionality where
you can have an yaml file like this:
config:
example_int: 17
And a java class like this:
public class Config {
int example_int;
config(example_int) {
this.example_int = example_int;
}
}
The framework would then (if I remember correctly) inject into the runtime
an instance of class Config with example_int data member initialized to 17.
I'm looking to implement a similar functionality in C++
i.e. parse a yaml file and then construct a c++ object based on the files contents.
While (I think) Spring uses runtime injection I think I could do this via meta programming to
reduce complexity.
TLDR:
Parse yaml with C++
Based on yaml configs inject an object into the runtime, or generate code via
metaprogramming, which has the characteristics defined in the yaml file.
I have a Json file and imported it to my resource folder in mulesoft. I am trying to pass it to mule java class to do some calculations with the values in it. Do i need Json to Object transformer or I can directly pass the Json data to java class? Flow explanation is really helpful. Thanks
of course you could pass JSON as string in your custom Java component, but it is more convenient to work with Java objects.
you can use json-to-object-transformer to convert your JSON to a generic Java object (java.util.Map) like this:
<flow name="flow">
<json:json-to-object-transformer returnClass="java.util.Map" doc:name="JSON to Object"/>
<!-- ... -->
</flow>
now the payload is a instance of java.util.HashMap containing the values from your JSON.
if you have a class representing the data in your JSON the replace java.util.Map with the fully qualified name of the class and json-to-object-transformer will return a instance of this class.
take a look at "Using the Transformers Explicitly" here: https://docs.mulesoft.com/mule-user-guide/v/3.7/native-support-for-json
In order to pass the JSON file to a json-to-object-transformer
you can also use parse-template component.
I have following xml
<root>
<child-1>
</child-1>
<child-2>
<subchild-21>
</subchild-22>
</child-2>
</root>
My requirement is such that I only want to parse child-2. I am unaware of root and child-1.
Is it possible with xstream because I couldn't find a way to ignore root.
There are several ways to go, depending on your requirements.
If you know the name of the class to parse (child-2 here), you could look for the <child-2> and </child-2> entry in the XML, copy them along with the content in-between to a new temporary XML file (you can create temporary files using createTempFile() from the standard File class). This is the way I would suggest.
If you want to take out the child-2 instance without knowing its name, but you know the names of the surrounding classes, you could mock their classes, that is create classes of the same name, but without their specific content. In your example there is no content (might have been ignored at export time), but it's important to have the same member data in the mock classes for the import to succeed. (unless you use ignoreUnknownElements() as stated by Philipi Willemann)
Of course, if you're the one creating the XML, you should be able to export only the child-2 instance in the first place.
If you know the root name you can create a simple class has an attribute of the class you have mapped to child-2:
#XStreamAlias("root")
class Root {
#XStreamAlias("child-2")
private Child2 child;
//get and set
}
Then when you are processing the XML you can set XStream to ignore unknown elements with xstream.ignoreUnknownElements();
I am just trying to find a way to be more flexible.
I have a java web-app that connects to a noSql db (couchbase). In order to map the stored jsons I have created a jar which contains all the java classes for all those jsons.
Rex json document
{
"age":15
}
Mapping the json structure to java class:
public class Dog{
private int age;
// getters+setters
}
The problem I am facing is:
Whenever I update the db json structure (because json is flexible) I have to update also the java classes -> recompile a new jar version of the classes (and update the web-app dependency to the new jar version).
A newly needed update for Rex json:
{
"dob":"1999/01/25",
"name":"Rex"
}
I need an update to the Dog class looking like this:
public class Dog{
private String dob;
private String name;
// getters+setters
}
How can I create the java classes to be flexibleand to not need a new recompilation of the classes jar?
My main objective is to not update/redeploy the web-apps connecting to noSql in case of an update of json structure.
Hoping this is not a dumb question, I thank you,
Georgian
You can use a Map<String, String> for storing these values
How can I create the java classes to be flexibleand to not need a new recompilation of the classes jar?
I assume that you need to read and write JSON using these classes ...
If so, you need to choose between:
a JSON <-> Java binding (like you are currently using) where you will need to generate new Java classes when your JSON structures change, OR
a JSON binding that binds JSON "objects" to a Map type, OR
something like the old "org.json" library where you load JSON into a JSONObject.
There is no way to get a statically typed API (like your Dog class) that automagically deals with changing JSON structures.