I cannot find any documentation on this, but it seems Gson serializes fields of sub-class before those of the super-class:
class G9 {
static class B { String s1 = "1"; String s2 = "2"; }
static class C extends B { String s3 = "3"; }
public static void main(String args[]) {
System.out.println(new Gson().toJson(new C()));
}
}
This program produces the following output:
/cygdrive/c/Java/jdk1.8.0/bin/javac -classpath gson-2.1.jar -g G9.java && /cygdrive/c/Java/jdk1.8.0/bin/java -classpath ".;gson-2.1.jar" G9
{"s3":"3","s1":"1","s2":"2"}
I would like it to be the following:
{"s1":"1","s2":"2","s3":"3"}
I realize I can do this with a TypeAdapter but that essentially amounts to
implementing serialization
figuring out how to delegate deserialization to Gson OR implementing that as well.
Is there an easier way to achieve this? I guess I am looking for a new FieldOrderingTypeAdapter<C>(C.class, "s1", "s2", "s3") or GsonBuilder.setFieldOrder("s1", "s2", "s3") or something.
I am using Gson 2.1.
From JSON order mixed up:
You cannot and should not rely on the ordering of elements within a
JSON object.
From the JSON specification at http://www.json.org/
An object is an unordered set of name/value pairs
As a consequence, JSON libraries are free to rearrange the order of
the elements as they see fit. This is not a bug.
As far as I know, there is no simple way to get around this.
Related
I'm wondering if I can declare an object in-line in Java like I can in JavaScript.
For example, in JavaScript I could say
let nameOfObject = {
anyKey: "my value",
someOtherValue: 5
};
console.log(nameOfObject.anyKey);// This logs "my value"
and this will create a classless object and assign nameOfObject as its "pointer" of sorts... How can I do this in Java? How do I create an object without a class?
I found one possible solution which looks like
Object nameOfObject = new Object(){
public String anyKey = "my value";
public int someOtherValue = 5;
};
System.out.println(nameOfObject.anyKey);
But that doesn't seem to compile, and says "anyKey cannot be resolved" and according to some other sources, will not work at all...
So I might be doing something very wrong, or maybe there's a different method, or maybe it's just straight up not possible with Java and I need to do it a different way...
class Some{
public String anyKey;
}
Some some = new Some() {
this.anyKey = "my value";
};
This code throws an error saying Syntax error, insert ";" to complete declaration, however
class Some{
public void anyMethod() {
}
}
Some some = new Some() {
public void anyMethod() {
System.out.println("Okay");
}
};
Works perfectly fine?
I don't understand what's going on here, but I would really appreciate an explanation and/or a solution (if one exists).
You can't really think of it as an "object" in Java. JavaScript objects are unique implementations of HashTables. If you want similar functionality, you can use a Java HashMap or ConcurrentHashMap(HashTable), depending on your specific requirements.
// we only add String->Double, but since you want to add "any type",
// we declare Map<Object, Object>
HashMap<Object, Object> map= new HashMap<>();
map.put("Zara", new Double(3434.34));
map.put("Mahnaz", new Double(123.22));
String[] names = map.keys();
while(names.hasMoreElements()) {
str = (String) names.nextElement();
System.out.println(str + ": " + map.get(str));
}
So, all objects in java have a class associated with them. Even raw Objects have a class: The Object class! You won't be able to create an object without a class because all values need to have a type of some sort. But that's really not a huge problem. If you need an object that stores certain values, you can just create a class that has space for those values. There's really no situation where you would not be able to do this.
That being said, if you just want a way of mapping keys to values, I'd recommend looking into the Map data structure.
JavaScript classes are different from Java classes, JavaScript is not a class-based object-oriented language, an object in JS is used as a template to hold properties, but in Java classes could hold variables (properties) and functions, so to initialize an object in Java there has to be a class for that object, you can think of it as a blueprint of how the object will be initiated for example to create a class:
public class Example {
public String link = "https://stackoverflow.com/";
public void printLink() {
System.out.println(link); // Prints the string stored in link
}
public void openLink() {
// Some code to open the link in the browser
}
}
To initialize an object from the class you created call this in your main or somewhere where the code will run:
Example example = new Example();
example.printLink(); // Printed the link
example.openLink(); // Opened the link
example.link = "https://example-link.com/"; // Changed the link
Note that the Example class could be in a different file and the file name has to be the same as the class name, here it is (Example.java)
Anyway if you are looking for an equivelant for JavaScript classes HashMap or HashTable could be very close.
I'm a beginner in programming, and I need some help. Is it possible to convert an HTTP (that returns a Json) automatic call to object in java? For example it reads the request, and when I call System.out.println (obj) it already returns me an OBJECT of this request, instead of String. Is it possible? If so, could you help me ... I already did the method to call the url and return string, but I need to return OBJECT, so I can compare with HashCode and Equals.
My code:
enter image description here
output:
{"header":{"messageId":"02938ec7-b2c3-4131-8ecf-3ad3a8509b41"},"body":{"products"
What I wanted: output
Informacoes [header=Header [messageId=66d22c00-bddc-4ea7-afbd-7c7225fcb914], body=Body
From what I can understand from your question, it looks like Gson might be useful. Gson is a library that allows you to convert between JSON and Java primitives/objects. Here's an example I just wrote:
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
}
public static void main(String[] args) {
Gson gson = new Gson();
String json = "{\"value1\":1,\"value2\":\"abc\"}";
BagOfPrimitives obj = gson.fromJson(json, BagOfPrimitives.class);
}
This code converts the json {"value1":1,"value2":"abc"} into an object of the class BagOfPrimitives.
To add Gson to your project, go here, click "Downloads" at the top right, and click "jar". Then follow these instructions to add the jar file to your project. Then you should be able to write import com.google.gson.* at the top of your class and use Gson in your java code.
I have the bunch of Java classes. I need to create simple POJOs of just the fields from Java classes. There is a way to create POJOs from JSON but I need directly from Java classes.
Java class may have logical methods and constructed based upon different things. My goal is just to hold the state in POJOs and send it over the network and deserialize in same set of POJOs.
You can serialize Java classes just fine, no need to strip them down to their fields (which is what it sounds like you want).
class MyClass implements Serializable {
private int myInt;
private String myString;
public MyClass(int mi, String ms) {
myInt = mi; myString = ms;
}
public String doStuff() { return String.format("%s %d", myString, myInt); }
}
Code for serialization:
MyClass toSerialize = new MyClass(5, "Test");
try (ObjectOutputStream out = new ObjectOutputStream(getNetworkOutstream())) {
out.writeObject(toSerialize);
}
Code to deserialize:
try (ObjectInputStream in = new ObjectInputStream(getNetworkInStream())) {
MyClass received = (MyClass) in.readObject();
}
The doStuff method is not in the way if that's what you're thinking.
Caveat is that all fields need to also be Serializable (or primitives).
If you are looking for a way to programmatically parse all those classes and generate POJOs for them, then you can use libraries like Antlr, JavaCC or JavaParser to analyse sources and then generate and save the new POJOs.
Use some JSON library.
For ex. GSON
You could choose what fields to serialize or not using transient identifier.
Apart from that these libraries offer much more and definitely all the requirements you specified.
I'm learning scala. I'm trying to find an easy way for turing JSON String to Scala case class instance. Java has wonderful library called Google Gson. It can turn java bean to json and back without some special coding, basically you can do it in a single line of code.
public class Example{
private String firstField
private Integer secondIntField
//constructor
//getters/setters here
}
//Bean instance to Json string
String exampleAsJson = new Gson().toJson(new Example("hehe", 42))
//String to Bean instance
Example exampleFromJson = new Gson().fromJson(exampleAsJson, Example.class)
I'm reading about https://www.playframework.com/documentation/2.5.x/ScalaJson and can't get the idea: why it's so complex is scala? Why should I write readers/writers to serialize/deserialize plain simple case class instances? Is there easy way to convert case class instance -> json -> case class instance using play json api?
Let's say you have
case class Foo(a: String, b: String)
You can easily write a formatter for this in Play by doing
implicit val fooFormat = Json.format[Foo]
This will allow you to both serialize and deserialize to JSON.
val foo = Foo("1","2")
val js = Json.toJson(foo)(fooFormat) // Only include the specific format if it's not in scope.
val fooBack = js.as[Foo] // Now you have foo back!
Check out uPickle
Here's a small example:
case class Example(firstField: String, secondIntField: Int)
val ex = Example("Hello", 3)
write(ex) // { "firstField": "Hello", "secondIntField" : 3 }
Code shown below works well when JSON object contains jsonKey as it was passed to the method. I wonder ... if there is a way to get a value assigned to a case insensitive representation of a key?
Example:
public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
return retrieveString(outputEvent, DESCRIPTION);
}
Should work regardless whether DESCRIPTION is defined as "Description", "description" or "DeScRipTIOn"
protected String retrieveString(JsonElement e, String jsonKey) throws ParserException {
JsonElement value = e.getAsJsonObject().get(jsonKey);
if (value == null) {
throw new ParserException("Key not found: " + jsonKey);
}
if (value.getAsString().trim().isEmpty()) {
throw new ParserException("Key is empty: " + jsonKey);
}
return e.getAsJsonObject().get(jsonKey).getAsString();
}
Unfortunately, registering a FieldNamingStrategy with the GsonBuilder wouldn't do much good, as it translates only in the opposite-than-desired direction: from the Java field name to the JSON element name. It cannot be reasonably used for your purposes.
(In Detail:
The result of the translation request ends at FieldNamingStrategy.translateName(Field), where the translated name is used to get the associated JSON element from a JsonObject, which has a LinkedHashMap<String, JsonElement>, called members, mapping JSON element names to their associated values. The translated name is used as the parameter to the get(String) method of members, and Gson provides no mechanism for this final call to be made case insensitive.
The members map is populated with calls to JsonObject.add(String, JsonElement), made from Streams.parseRecursive(JsonReader), with the JSON element name retrieved from the JsonReader used as the key to 'members'. (JsonReader uses the characters exactly as they are in the JSON, with the exception where the escape character '\' is found.) Throughout this call stack, Gson provides no mechanism for the keys used to populate members to be altered, e.g., to be made all lower case or all upper case.
A FieldNamingPolicy works in the same way.)
A reasonable solution might be to simply use a custom deserializer, along the following lines.
input.json:
[
{"field":"one"},
{"Field":"two"},
{"FIELD":"three"},
{"fIElD":"four"}
]
Foo.java:
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class Foo
{
public static void main(String[] args) throws Exception
{
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyClass.class, new MyTypeAdapter());
Gson gson = gsonBuilder.create();
MyClass[] myObjects = gson.fromJson(new FileReader("input.json"), MyClass[].class);
System.out.println(gson.toJson(myObjects));
}
}
class MyClass
{
String field;
}
class MyTypeAdapter implements JsonDeserializer<MyClass>
{
#Override
public MyClass deserialize(JsonElement json, Type myClassType, JsonDeserializationContext context)
throws JsonParseException
{
// json = {"field":"one"}
JsonObject originalJsonObject = json.getAsJsonObject();
JsonObject replacementJsonObject = new JsonObject();
for (Entry<String, JsonElement> elementEntry : originalJsonObject.entrySet())
{
String key = elementEntry.getKey();
JsonElement value = originalJsonObject.get(key);
key = key.toLowerCase();
replacementJsonObject.add(key, value);
}
return new Gson().fromJson(replacementJsonObject, MyClass.class);
}
}
Alternatively, you could first process the raw JSON to alter all of the element names to be the same case, all lower or all upper. Then, pass the altered JSON to Gson for deserialization. This would of course slow down JSON processing.
If you're able to change Gson code for your project, then probably the part to change for the most efficient result is the call to name = nextString((char) quote); in JsonReader. Since nextString(char) is also used to get the JSON element value, I'd probably just make a copy of it for getting the name, and then make small changes to force the element names to all lower or all upper case. Of course, this approach then locks your project to one release of Gson, else you'd need to repeat this change to upgrade to a newer Gson release.
With Jackson, the situation appears unfortunately similar. Translations with a PropertyNamingStrategy work in unfortunately much the same way: they translate from the Java field name to the JSON element name. None of the available JsonParser.Feature alterations would customize a JsonParser to force JSON element names to all upper or all lower case.
I faced the similar issue. I did this to get around the issue. (Replaced all the keys with their corresponding lowercase version and had all lower case fields in matching class). Hope this helps.
input = input.replaceAll("\\s","");
Matcher m = Pattern.compile("\"\\b\\w{1,}\\b\"\\s*:").matcher(input);
StringBuilder sanitizedJSON = new StringBuilder();
int last = 0;
while (m.find()) {
sanitizedJSON.append(input.substring(last, m.start()));
sanitizedJSON.append(m.group(0).toLowerCase());
last = m.end();
}
sanitizedJSON.append(input.substring(last));
input = sanitizedJSON.toString();
Unfortunately there doesn't seem to be a way in the current implementation to do this. If you look at the Gson source and more specifically at the JsonObject implementation you will see that the underlying data structure is a linked hash map. The get call simply invokes the get on the map, which in turn uses the hash code and equals method of your key to find the object you are looking for.
The only way around is to enforce some naming conventions for you keys. The easiest way would be to force all the keys to lowercase. If you need mixed case keys then you will have more difficulty and will need to write a more sophisticated algorithm for transforming the keys instead of simply calling jsonKey.toLowerCase().
I stumbled across this question when I ran into an issue where a different naming convention was being used at the two endpoints and subsequently discovered a less invasive solution.
Gson does support setting a naming convention that is used when mapping from the Java model names to the JSON names, both when when serializing and deserializing. Use the setFieldNamingPolicy method of the builder to change this behavior.
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
Gson gson = gsonBuilder.create();
See here for a nice article on the subject, including an overview of the different policies.
This isn't really a case insensitive solution, but it does provide a way to work around many of the situations where the case is not matching up.