I'm trying to find a simple/efficient way to store multiple values under each index for my application, for example:
1 = {54, "Some string", false, "Some other string"}
2 = {12, "Some string", true, "Some other string"}
3 = {18, "Some string", true, "Some other string"}
So that I can set this as a static variable which can then be accessed from various object instances via the single index value (the only variable within each object). Essentially, sort of like a "multi dimensional dictionary".
I have looked at 2D arrays, but they seem to be limited to single data types (Int, string, etc) and also looked at hash maps - which also seemed limited as if using more than two values, would require a list variable which again comes back the the single data type problem. Any advice on a simple solution for this please?
Define a class for those entries, and use an array of objects. So the class might be something like:
class Thingy {
private int someNumber;
private String someString;
private boolean someBool;
private String someOtherString;
public Thingy(int _someNumber, String _someString, boolean _someBool, String _someOtherString) {
this.someNumber = _someNumber;
this.someString = _someString;
this.someBool = _someBool;
this.someOtherString = _someOtherString;
}
public int getSomeNumber() {
return this.someNumber;
}
// ...setter if appropriate...
// ...add accessors for the others...
}
...and then you do:
Thingy[] thingies = new Thingy[] {
new Thingy(54, "Some string", false, "Some other string"),
new Thingy(12, "Some string", true, "Some other string"),
new Thingy(18, "Some string", true, "Some other string")
};
The backbone of Python heavily relies on dictionary data structures, many instances can be reflected, assigned and accessed through using the __dict__ attribute. If you have a model that frequently has to access a dozen dictionaries or so, replicating something like the following in Python would reduce quite a lot of the unnecessary Java idiosyncrasies:
class ExampleObject:
spam = "example"
title = "email title"
content = "some content"
obj = ExampleObject()
print obj.spam # prints "example"
print obj.__dict__["spam"] # also prints "example"
Just throwing an alternative option out there for you.
Related
I have a set of picocli-based applications that I'd like to parse the usage output into structured data. I've written three different output parsers so far and I'm not happy with any of them (fragility, complexity, difficulty in extending, etc.). Any thoughts on how to cleanly parse this type of semi-structured output?
The usage output generally looks like this:
Usage: taker-mvo-2 [-hV] [-C=file] [-E=file] [-p=payoffs] [-s=millis] PENALTY
(ASSET SPREAD)...
Submits liquidity-taking orders based on mean-variance optimization of multiple
assets.
PENALTY risk penalty for payoff variance
(ASSET SPREAD)... Spread for creating market above fundamental value
for assets
-C, --credential=file credential file
-E, --endpoint=file marketplace endpoint file
-h, --help display this help message
-p, --payoffs=payoffs payoff states and probabilities (default: .fm/payoffs)
-s, --sleep=millis sleep milliseconds before acting (default: 2000)
-V, --version print product version and exit
I want to capture the program name and description, options, parameters, and parameter-groups along with their descriptions into an agent:
public class Agent {
private String name;
private String description = "";
private List<Option> options;
private List<Parameter> parameters;
private List<ParameterGroup> parameterGroups;
}
The program name is taker-mvo-2 and the (possibly multi-lined) description is after the (possibly multi-line) arguments list:
Submits liquidity-taking orders based on mean-variance optimization of multiple assets.
Options (in square brackets) should be parsed into:
public class Option {
private String shortName;
private String parameter;
private String longName;
private String description;
}
The parsed options' JSON is:
options: [ {
"shortName": "h",
"parameter": null,
"longName": "help",
"description": "display this help message"
}, {
"shortName": "V",
"parameter": null,
"longName": "version",
"description": "print product version and exit"
}, {
"shortName": "C",
"parameter": file,
"longName": "credential",
"description": "credential file"
}, {
"shortName": "E",
"parameter": file,
"longName": "endpoint",
"description": "marketplace endpoint file"
}, {
"shortName": "p",
"parameter": payoffs,
"longName": "payoffs",
"description": "payoff states and probabilities (default: ~/.fm/payoffs)"
}]
Similarly for the parameters which should be parsed into:
public class Parameter {
private String name;
private String description;
}
and parameter-groups which are surrounded by ( and )... should be parsed into:
public class ParameterGroup {
private List<String> parameters;
private String description;
}
The first hand-written parser I wrote walked the buffer, capturing the data as it progresses. It works pretty well, but it looks horrible. And it's horrible to extend. The second hand-written parser uses regex expressions while walking the buffer. Better looking than the first but still ugly and difficult to extend. The third parser uses regex expressions. Probably the best looking of the bunch but still ugly and unmanageable.
I thought this text would be pretty simple to parse manually but now I'm wondering if ANTLR might be a better tool for this. Any thoughts or alternative ideas?
Model
It sounds like what you need is a model. An object model that describes the command, its options, option parameter types, option description, option names, and similar for positional parameters, argument groups, and potentially subcommands.
Then, once you have an object model of your application, it is relatively straightforward to render this as JSON or as some other format.
Picocli has an object model
You could build this yourself, but if you are using picocli anyway, why not leverage picocli's strengths and use picocli's built-in model?
CommandSpec
OptionSpec
PositionalParamSpec
ArgGroupSpec
and more...
Accessing picocli's object model
Commands can access their own model
Within a picocli-based application, a #Command-annotated class can access its own picocli object model by declaring a #Spec-annotated field. Picocli will inject the CommandSpec into that field.
For example:
#Command(name = "taker-mvo-2", mixinStandardHelpOptions = true, version = "taker-mvo-2 0.2")
class TakerMvo2 implements Runnable {
// ...
#Option(names = {"-C", "--credential"}, description = "credential file")
File file;
#Spec CommandSpec spec; // injected by picocli
public void run() {
for (OptionSpec option : spec.options()) {
System.out.printf("%s=%s%n", option.longestName(), option.getValue());
}
}
}
The picocli user manual has a more detailed example that uses the CommandSpec to loop over all options in a command to see if the option was defaulted or whether a value was specified on the command line.
Creating a model of any picocli command
An alternative way to access picocli's object model is to construct a CommandLine instance with the #Command-annotated class (or an object of that class). You can do this outside of your picocli application.
For example:
class Agent {
public static void main(String... args) {
CommandLine cmd = new CommandLine(new TakerMvo2());
CommandSpec spec = cmd.getCommandSpec();
// get subcommands
Map<String,CommandLine> subCmds = spec.subcommands();
// get options as a list
List<OptionSpec> options = spec.options()
// get argument groups
List<ArgGroupSpec> argGroups = spec.argGroups()
...
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I need help extracting a JSON array string into an array of objects so that it can be later processed.
The JSON string is embedded as a value within a pipe delimited string that is itself an XML element value.
A sample string is as below
<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}</MSG>
How can I extract the JSON properties and store them in separate arrays like
Format[0] =BMP
Position[0] =RIGHT_INDEX
Data[0]=Qk12WQEAAAAAADYAAAA=
Format[1] =BMP
Position[1]=LEFT_INDEX
Data[1]= Qk12WQEADoAAAA
These objects would then be passed to a separate function like below
FingerprintImage(Format[0],Position[0],Data[0]);
// ...
FingerprintImage(Format[1],Position[1],Data[1]);
// ...
public FingerprintImage(String format, String position, String data) {
setFormat(format);
setPosition(position);
setData(data);
}
I am not a java developer, the following is hopefully helpful to yourself or others who can provide more succinct syntax in java.
Firstly, we should identify there different layers of data serialization going on with your value:
<MSG></MSG> This is an outer XML element, so the first step is to interpret this value as an XML fragment and extract the XML Value.
The reason that we use XML deserialization at this top level, and not just use the string position, is that the inner values may have been XML escaped, so we need to parse the inner value using the XML encoding rules.
This leaves us with the strimg value: registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
The next level is pipe-delimited, which is the same as CSV, except the escape character is a | and usually there is no other encoding rules, as | isn't considered part of the normal lexical domain and we shouldn't need any further escaping.
You could therefore split this string into an array.
The value we are interested in is the 15th element in the array, eithe you know this in advance, or you could simply iterate through the elements to find the first one that starts with {
This leaves a JSON value: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
Now that we have isolated the inner value in JSON format, the usual thing to do next is deserialize this value into an object.
I know OP is asking for arrays, but we can realize JSON objects as arrays if we really want to with the right tools.
In C# the above process is pretty simple, I'm sure it should be in Java as well, but my attempts keep throwing errors.
So, lets instead assume (I know... Ass-U-Me...) that there is only ever a single JSON value in the pipe-delimited array, with this knoweldge we can isolate the JSON using int String.IndexOf(str)
String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
int start = xml.indexOf('{');
int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
String json = xml.substring(start, end);
results in: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}}
Formatted to be pretty:
{
"biometrics": {
"fingerprints": {
"fingerprints": [
{
"position": "RIGHT_INDEX",
"image": {
"format": "BMP",
"resolutionDpi": "508",
"data": "Qk12WQEAAAAAADYAAAA="
}
},
{
"position": "LEFT_INDEX",
"image": {
"format": "BMP",
"resolutionDpi": "508",
"data": "Qk12WQEADoAAAA"
}
}
]
}
}
}
One way would be to create a class structure that matches this JSON value, then we can simply .fromJson() for the whole value, instead, lets meet halfway so we only need to define the inner class structure for the data we will actually use.
Now from this structure we can see there is an outer object that only has a single property called biometrics, this value is again an object witha single property called fingerprints. The value of this property is another object that has a single property called fingerprints except that this time it has an array value.
The following is a proof in Java, I have included first an example using serialization (using the gson library) and after that a similar implementation using only the simple-JSON library to read the values in arrays.
Try it out on JDoodle.com
MyClass.java
import java.util.*;
import java.lang.*;
import java.io.*;
//import javax.json.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.google.gson.Gson;
public class MyClass {
public static void main(String args[]) {
String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>";
int start = xml.indexOf('{');
int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it
String jsonString = xml.substring(start, end);
JSONParser parser = new JSONParser();
Gson gson = new Gson();
try
{
// locate the fingerprints inner array using simple-JSON (org.apache.clerezza.ext:org.json.simple:0.4 )
JSONObject jsonRoot = (JSONObject) parser.parse(jsonString);
JSONObject biometrics = (JSONObject)jsonRoot.get("biometrics");
JSONObject fpOuter = (JSONObject)biometrics.get("fingerprints");
JSONArray fingerprints = (JSONArray)fpOuter.get("fingerprints");
// Using de-serialization from gson (com.google.code.gson:gson:2.8.6)
FingerPrint[] prints = new FingerPrint[fingerprints.size()];
for(int i = 0; i < fingerprints.size(); i ++)
{
JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
prints[i] = gson.fromJson(fpGeneric.toString(), FingerPrint.class);
}
// Call the FingerprintImage function using the FingerPrint objects
System.out.print("FingerPrint Object Index: 0");
FingerprintImage(prints[0].image.format, prints[0].position, prints[0].image.data );
System.out.println();
System.out.print("FingerPrint Object Index: 1");
FingerprintImage(prints[1].image.format, prints[1].position, prints[1].image.data );
System.out.println();
// ALTERNATE Array Implementation (doesn't use gson)
String[] format = new String[fingerprints.size()];
String[] position = new String[fingerprints.size()];
String[] data = new String[fingerprints.size()];
for(int i = 0; i < fingerprints.size(); i ++)
{
JSONObject fpGeneric = (JSONObject)fingerprints.get(i);
position[i] = (String)fpGeneric.get("position");
JSONObject image = (JSONObject)fpGeneric.get("image");
format[i] = (String)image.get("format");
data[i] = (String)image.get("data");
}
System.out.print("Generic Arrays Index: 0");
FingerprintImage(format[0], position[0], data[0] );
System.out.println();
System.out.print("Generic Arrays Index: 1");
FingerprintImage(format[1], position[1], data[1] );
System.out.println();
}
catch (ParseException ignore) {
}
}
public static void FingerprintImage(String format, String position, String data) {
setFormat(format);
setPosition(position);
setData(data);
}
public static void setFormat(String format) {
System.out.print(", Format=" + format);
}
public static void setPosition(String position) {
System.out.print(", Position=" + position);
}
public static void setData(String data) {
System.out.print(", Data=" + data);
}
}
output
FingerPrint.java
public class FingerPrint {
public String position;
public FingerPrintImage image;
}
FingerPrintImage.java
public class FingerPrintImage {
public String format;
public int resolutionsDpi;
public String data;
}
Deserialization techniques are generally considered superior to forced/manual parsing especially when we need to pass around references to multiple parsed values. In the above example, by simply reading format, position and data into separate arrays, the relationship between them has become de-coupled, through our code implementation we can still use them together as long as we use the same array index, but the structure no longer defines the relationship between the values. De-serializing into a typed structure preserves the relationship between values and simplifies the task of passing around values that are related to each other.
update
If you used serialization, then you could pass through the equivalent FingerPrint object to any methods that need it, instead of passing through the related values individually, further to this you could simply pass around the entire array of FingerPrint objects.
public static void FingerprintImage(FingerPrint print) {
setFormat(print.image.format);
setPosition(print.position);
setData(print.image.data);
}
To process multiple FingerPrint objects in a batch, change the method to accept an array: FingerPrint[]
You could use the same technique to process arrays or each of the Format, Postion and Data, though it is really poor practise to do so. Passing around multiple arrays and expecting the receiving code to know that each of the arrays is supposed to be interpreted in sync, that is the same index in each array corresponds to the same finger print, this level of implementation detail is too ambiguous and will lead to maintenance nightmares down the track, its far better to learn and become proficient in OO concepts and creating business objects for passing around related data elements, instead of packaging everything into disassociated arrays.
The following code can assist you in processing multiple items using OPs array method but it should highlight why the practise is a bad habit to pickup:
public static void FingerprintImage(String[] formats, String[] positions, String[] datas) {
// now you must iterate each of the arrays using the same index
// however as there are no restrictions on the arrays, for each array
// and each index we should be checking that the array has not gone out
// of length.
}
From an OO point of view, passing through multiple arrays like this raises a number of issues, firstly, the developer will simply need to know that the same index must be used in each array to retrieve correlated information.
The next important issue is error handling...
If datas only has 1 element, but positions has 2 elements, which of the 2 elements does the 1 data element belong to? Or does this indicate that the same data should be used for both?
There are many other issues, consider when you expect 3 elements...
While you can get away with what seems like a shortcut in code if you really need to, you really shouldn't unless you absolutely understand what you are doing, you fully document the related code and you are taking responsibility for the potential fall out down the track.
Is there any String replacement mechanism in Java, where I can pass objects with a text, and it replaces the string as it occurs?
For example, the text is:
Hello ${user.name},
Welcome to ${site.name}.
The objects I have are user and site. I want to replace the strings given inside ${} with its equivalent values from the objects. This is same as we replace objects in a velocity template.
Use StringSubstitutor from Apache Commons Text.
Dependency import
Import the Apache commons text dependency using maven as bellow:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
Example
Map<String, String> valuesMap = new HashMap<String, String>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);
Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, then inserts the formatted strings into the pattern at the appropriate places.
Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
My preferred way is String.format() because its a oneliner and doesn't require third party libraries:
String message = String.format("Hello! My name is %s, I'm %s.", name, age);
I use this regularly, e.g. in exception messages like:
throw new Exception(String.format("Unable to login with email: %s", email));
Hint: You can put in as many variables as you like because format() uses Varargs
I threw together a small test implementation of this. The basic idea is to call format and pass in the format string, and a map of objects, and the names that they have locally.
The output of the following is:
My dog is named fido, and Jane Doe owns him.
public class StringFormatter {
private static final String fieldStart = "\\$\\{";
private static final String fieldEnd = "\\}";
private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
private static final Pattern pattern = Pattern.compile(regex);
public static String format(String format, Map<String, Object> objects) {
Matcher m = pattern.matcher(format);
String result = format;
while (m.find()) {
String[] found = m.group(1).split("\\.");
Object o = objects.get(found[0]);
Field f = o.getClass().getField(found[1]);
String newVal = f.get(o).toString();
result = result.replaceFirst(regex, newVal);
}
return result;
}
static class Dog {
public String name;
public String owner;
public String gender;
}
public static void main(String[] args) {
Dog d = new Dog();
d.name = "fido";
d.owner = "Jane Doe";
d.gender = "him";
Map<String, Object> map = new HashMap<String, Object>();
map.put("d", d);
System.out.println(
StringFormatter.format(
"My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.",
map));
}
}
Note: This doesn't compile due to unhandled exceptions. But it makes the code much easier to read.
Also, I don't like that you have to construct the map yourself in the code, but I don't know how to get the names of the local variables programatically. The best way to do it, is to remember to put the object in the map as soon as you create it.
The following example produces the results that you want from your example:
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
Site site = new Site();
map.put("site", site);
site.name = "StackOverflow.com";
User user = new User();
map.put("user", user);
user.name = "jjnguy";
System.out.println(
format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}
I should also mention that I have no idea what Velocity is, so I hope this answer is relevant.
Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.
Create a map of all the objects that will be referenced in the template.
Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.
There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL
I like and have successfully used MVEL in at least one project.
Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context
Handlebars.java might be a better option in terms of a Velocity-like syntax with other server-side templating features.
http://jknack.github.io/handlebars.java/
Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));
I use GroovyShell in java to parse template with Groovy GString:
Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
I created this utility that uses vanilla Java. It combines two formats... {} and %s style from String.format.... into one method call. Please note it only replaces empty {} brackets, not {someWord}.
public class LogUtils {
public static String populate(String log, Object... objects) {
log = log.replaceAll("\\{\\}", "%s");
return String.format(log, objects);
}
public static void main(String[] args) {
System.out.println(populate("x = %s, y ={}", 5, 4));;
}
}
Since Java 15 you have the method String.formatted() (see documentation).
str.formatted(args) is the equivalent of String.format(str, args) with less ceremony.
For the example mentioned in the question, the method could be used as follows:
"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())
Good news. Java is most likely going to have string templates (probably from version 21).
See the string templates proposal (JEP 430) here.
It will be something along the lines of this:
String name = "John";
String info = STR."I am \{name}";
System.out.println(info); // I am John
P.S. Kotlin is 100% interoperable with Java. It supports cleaner string templates out of the box:
val name = "John"
val info = "I am $name"
println(info) // I am John
Combined with extension functions, you can achieve the same thing the Java template processors (e.g. STR) will do.
There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter
http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html
However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).
I'm using Gson to parse a JSON string. I want to convert this to an object using a container class and embedded static classes. To some extent this has been possible, but I want to treat the content of stuff1 and stuff2 as arrays, for example, stuff1 is an array containing other_stuff1 and other_stuff2. This is so I can reference the object in a fashion like these: object.integer, object.stuff1.get("other_stuff1").name, or object.stuff2.get("other_stuff3").more. (for the last one, I could be interested in looping over more to get each item.
For example, in PHP, I would use this:
<?php
echo "<pre>";
$object = json_decode(file_get_contents("THE JSON FILENAME"));
foreach($object->stuff1 as $name=>$data) {
echo $name . ":\n"; // other_stuff1 or other_stuff2
echo $unlockable->description . "\n\n"; // Got lots of stuff or Got even more stuff.
}
?>
I want to be able to reference in a similar way, loading the JSON to an object to be used on the fly.
It is crucial that, while some degree of change can be made to the JSON, that the names of the elements remain and be referable and retrievable.
I've included JSON, very similar to the one I'm using, below.
{
"integer":"12345",
"stuff1":{
"other_stuff1":{
"name":"a_name",
"description":"Got lots of stuff.",
"boolean":false
},
"other_stuff2":{
"name":"another_name",
"description":"Got even more stuff",
"boolean":true
}
},
"stuff2":{
"other_stuff3":{
"name":"a_name",
"description":"Got even more stuff",
"boolean":false,
"more":{
"option1":{
"name":"hello"
},
"option2":{
"name":"goodbye"
}
}
},
}
}
I've gone through a number of reference guides and tutorials, and I can't find a way to interpret this the way I'm trying to.
I'd really appreciate it if someone could give me a pointer. I can't find any tutorials that take into account that a) I want multiple objects in an array-style list, referable by the IDs (like with other_stuff1 and other_stuff2), and b) I want to also be able to loop over the items without providing the IDs.
You should define a Java class with fields named after the keys you need. You can use Maps (not arrays) to get the .get("key") behavior you describe. For example:
class Container {
private final int integer;
private final HashMap<String, Stuff> stuff1;
private final HashMap<String, Stuff> stuff2;
}
class Stuff {
private final String name;
private final String description;
#SerializedName("boolean") private final boolean bool;
private final HashMap<String, Option> more;
}
class Option {
private final String name;
}
For the "boolean" field you need need to use a different variable name since boolean is a reserved keyword.
You can then do:
Container c = gson.fromJson(jsonString, Container.class);
for(Stuff s : c.getStuff1().values()) {
System.out.println(s.getName());
}
I'm translating a Java program to vb.net where settings in the application is controlled by a enum.
private enum SmsTagRule {
// KEYWORD DOMAIN BusinessClass PREFIX SEARCHNAME SEARCHPARAM SENDEMAIL KEYWORDS...
BAG_TAG("BagTag", "BagTag", "FoundBagTag", "b", "SearchBagTag", "490_TagNumber", true, "BagTag"),
SKI_TAG("SkiTag", "SkiTag", "FoundSkiTag", "a", "SearchSki", "518_LabelNo", false, "SkiTag", "ski"),
PC_TAG("PcTag", "ds", "FoundPC", "", "SearchPcTag", "585_LabelNo", false, "pc");
And depending on witch "TAG" in chosen different settings are getting returned. Is there any way to do this in vb.NET. I have thought about creating one enum for each one of these TAG's but it seems like it should be a better solution to this.
Any Ideas?
Go on and create a custom Type representing your settings:
Class TagRule
Public Shared BAG = new TagRule("BagTag", "BagTag", "FoundBagTag", ...)
Public Shared Ski = new TagRule("SkiTag", "SkiTag", "FoundSkiTag", ...)
...
Dim _keyword As String
Public Property Keyword as String
Public Get
return _keyword
End
Private Set
_keyword = value
End
End Property
...
Private Sub New(keyword as String, domain as String, businessclass as String, ...)
_keyword = keyword
_domain = domain
....
End Sub
End Class
And you can use it like this:
Dim setting As TagRule = Nothing
If somecondition Then
setting = TagRule.Ski
Else
setting = TagRule.BAG
End If
Dim keyword = setting.Keyword
Dim domain = setting.Domain