Overwriting one Json config on another in Java - java

I have base config file x.json which is something like
{
"key-i" : "value-i",
"key-ii" : {
"key-ii-a" : "value-ii-a",
"key-ii-b" : {
"key-ii-b-1" : "value-ii-b-1",
"key-ii-b-2" : "value-ii-b-2"
}
}
}
and another env specific config file x_env.json which is something like
{
"key-ii" : {
"key-ii-b" : {
"key-ii-b-2" : "different-value-ii-b-2"
}
}
}
Now I want to overwrite only config present in x_env.json on top of x.json which should look like
{
"key-i" : "value-i",
"key-ii" : {
"key-ii-a" : "value-ii-a",
"key-ii-b" : {
"key-ii-b-1" : "value-ii-b-1",
"key-ii-b-2" : "different-value-ii-b-2"
}
}
}
This is only an example and x.json can be any json and how can I generically overwrite x_env.json on x.json for any json structure in Java.
I am using the gson library and following to parse
JsonParser.parseString(IOUtils.toString(ClassName.class.getResourceAsStream("x.json"))).getAsJsonObject();

Related

Using Jaca JsonPath to exclude items from JSON response

I am using the JsonSmartJsonProvider and my JSON looks like this
{
"info": {
"clientCount": 1,
"compactorVersion": 2,
"processMonitor": {
"processList": [
{
"name": "java.exe",
"commandLine": "",
"pid": 6224
}
]
}
}
}
I'm trying to exclude "processList", but keep everything else. I've tried variations on $.info[?(# noneof ['processMonitor'])], but I always end up with "info" being empty in the response. Is it possible to use JsonPath to do this? The code that is used to do this looks like this:
DocumentContext document = JsonPath.using(CONFIGURATION).parse(json);
Map<String, Object> result = new HashMap<>();
paths.forEach((key, value) -> result.put(key, document.read(value)));
return result;
As mentioned, you are actually looking for a JSON transformation. JOLT is a common library to do just that. A solution can look like this:
import java.util.List;
import com.bazaarvoice.jolt.Chainr;
import com.bazaarvoice.jolt.JsonUtils;
public class MyJsonTransformer {
public static void main(String[] args) throws Exception {
List<Object> specs = JsonUtils.classpathToList("/spec.json");
Chainr chainr = Chainr.fromSpec(specs);
Object inputJSON = JsonUtils.classpathToObject("/input.json");
Object transformedOutput = chainr.transform(inputJSON);
System.out.println(JsonUtils.toPrettyJsonString(transformedOutput));
}
}
And a jolt remover spec file like this:
[
{
"operation": "remove",
"spec": {
"info": {
"processMonitor": {
"processList": ""
}
}
}
}
]
You can try JOLT online with your input and the spec above here. Pretty neat.
The JSON and spec can be defined inline as well. I have not tested this end to end.

Constant path replacement for different environments using gradle

This is a Apache Storm based project. I have a Constants file which looks something like this
public class Constant {
public static final String CONTEXT_PATH ="<some path to a context.xml file>";
public static final String APP_PROPERTIES_PATH = "<path to the properties file>";
//...More static properties
}
This CONTEXT_PATH variable is different for different environments (dev, test, prod).
I have a gradle task which generates the JAR file for deployment
task stormJar(type: Jar) {
baseName = 'diagnostic'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
I was looking to dynamically change or refer the CONTEXT_PATH variable so that we can create builds for different environments without making any changes to this file.
I believe there are solutions to do so in the Android territory (BuildConfig), but not able to find a solution for a plain Java project.
The solution should be such, it should work for IDE (IntelliJ and Eclipse) as well as create environment specific build.
Doing something like below should get the work done
gradlew build -pEnvironment=prod
Not much experience with gradle. Please point me in the right direction.
Note there is a working example here.
One technique is to generate Constants.java as part of the build. Consider this template (stored as a resource, not as Java code):
public class Constants {
public static final String CONTEXT_PATH = "__CONTEXT_PATH";
public static final String APP_PROPERTIES_PATH = "__APP_PROPERTIES_PATH";
}
and the following generates Constants.java early in the compileJava task:
compileJava.doFirst {
def newConstantsFile = new File("${projectDir}/src/main/java/net/codetojoy/util/Constants.java")
def templateConstantsFile = new File("${projectDir}/resources/TemplateConstants.java")
newConstantsFile.withWriter { def writer ->
templateConstantsFile.eachLine { def line ->
def newLine = line.replace("__PACKAGE", "net.codetojoy.util")
.replace("__CONTEXT_PATH", getContextPath())
.replace("__APP_PROPERTIES_PATH", getAppPropertiesPath())
writer.write(newLine + "\n");
}
}
}
and then the crucial env-specific predicates:
def getContextPath = { ->
def result = "default"
if (project.Environment == "prod") {
result = "PROD context path here"
} else if (project.Environment == "uat") {
result = "UAT context path here"
} else if (project.Environment == "dev") {
result = "DEV context path here"
}
return result
}
def getAppPropertiesPath = { ->
def result = "default"
if (project.Environment == "prod") {
result = "PROD app properties path here"
} else if (project.Environment == "uat") {
result = "UAT app properties path here"
} else if (project.Environment == "dev") {
result = "DEV app properties path here"
}
return result
}
Note that the ENV-specific values could easily be abstracted into config files, ENV vars, etc.
Also note that the example addresses: Java package used, project version, and build timestamp as well. I write something like this for most projects.

is it possible use multi type in Class

I need to response a tree structure by json,
in my object,
{
MyClass 1:[{MyClass 11},{MyClass 12}],
MyClass 2:[{MyClass 21},{MyClass 22}],
MyClass 3:[{MyClass 31},{MyClass 32},
{MyClass 33 :[{MyClass 331},{MyClass 332}]}
]
}
I used a HashMap<MyClass, ArrayList<Object>> to do this
and it worked, but when I trans to Json by Gson().toJson
it show {MyClass Format: object Format}
like this
{
"{Id=1, Name=HQS, parentId=0, level=1}":[
{
"_Id":5,
"_Name":"ADM",
"_originalName":"ADM",
"_parentId":1,
"_originalParentId":1,
"_setOriginalParentId":false,
"_level":2,
"_originalLevel":2,
"_setOriginalLevel":false,
"_columnBitmask":0,
"_cachedModel":false,
"_new":false
},
{
"{Id=2, Name=HQS, parentId=1, level=2}":[
{
"_Id":21,
"_Name":"ADMS",
"_originalName":"ADMS",
"_parentId":2,
"_originalParentId":2,
"_setOriginalParentId":false,
"_level":3,
"_originalLevel":3,
"_setOriginalLevel":false,
"_columnBitmask":0,
"_cachedModel":false,
"_new":false
}
]
}
]
}
I guess the point is Object, how could I fix it to show my class format?

Control how an elasticsearch java QueryBuilder is converted into a String

The following code emits an elasticsearch query that is too verbose for my liking -
import org.elasticsearch.index.query.QueryBuilder;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
public class MyQueryPrinter {
public static void main(String[] args) {
QueryBuilder myQuery = termQuery("brand", "gucci");
System.out.println(myQuery.toString());
/* prints -
{
"term" : {
"brand" : {
"value" : "gucci",
"boost" : 1.0
}
}
}
*/
}
}
I'd like to print the shortest possible query json-
{
"term" : {
"brand" : "gucci"
}
}
The code also automatically "pretty-prints" (i.e. indents) the json.
How can I control how QueryBuilder is converted into a String?
Thanks!!
p.s. - I'm using Elasticsearch 5.5.3 via maven -
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.5.3</version>
</dependency>

Getting location of cross-project resources

I have read many similar questions where the reply is that the project structure is not ideal so my questions based on the following:
I have a main project (ProjA) which needs to include a second project (ProjB) which is not a child project. ProjB has various resource files which need to be copied in the distribution of ProjA.
build.gradle of ProjA
dependencies {
compile project(":ProjB")
}
distributions {
main {
baseName = "Something"
contents {
into('bin') { from jar.archivePath }
into('lib') { from configurations.runtime }
into('etc') {
from ('../../projb/src/main/webapp') // Fix me!
}
}
}
}
1.) Ideally ProjB should expose the location of the resource files through a property used by ProjA, how can this be done?
2.) Is this the correct way to do it as I have read alot about cross-project properties not being ideal - or should I be doing something completely different?
Don't know if it helps but it seems that the best way is to do it in the following way:
distributions {
main {
baseName = "Something"
contents {
into('bin') { from jar.archivePath }
into('lib') { from configurations.runtime }
into('etc') {
from project(':projB').file('src/main/webapp')
}
}
}
}
The path must be hardcoded in that case.
Second option might be specifying a project property - in general not a very good idea - and use in another project - there must be also evaluation order defined.
In projB
ext.resourcesDir = project.file('src/main/webapp2')
and in projA
evaluationDependsOn(':projB')
and:
distributions {
main {
baseName = "Something"
contents {
into('bin') { from jar.archivePath }
into('lib') { from configurations.runtime }
into('etc') {
from project(':projB').file('src/main/webapp')
from project(':projB').resourcesDir
}
}
}
}
Here's complete example.

Categories

Resources