I am trying to read a JSON file to create a new Object. I can read all the Strings in it but i throws a ClassCastException when trying to read an int. Here is the JSON file.
{"id1" : "string1",
"id2": "string2",
"id3": 100.0
}
And here is the java code.
public static Aparelho novoAparelho(JSONObject obj) {
Aparelho ap = null;
String tipe = (String) obj.get("id1");
String name = (String) obj.get("id2");
if(tipe.equals("anyString")) {
int pot = (int) obj.get("id3");
ap = new SomeObject(name, pot);
}
return ap;
}
It throws.
Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
Cast it to double first:
int pot = (int) (double) obj.get("id3");
ap = new SomeObject(name, pot);
Confusingly, there are three kinds of casts:
Those that convert values of primitives
Those that change the type of a reference
Those that box and unbox
In this case, you have an Object (which is actually a boxed Double), and you want a primitive int. You can't unbox and convert with the same cast, so we need two casts: first from Object to double (unboxing), and one from double to int (conversion).
Integers don't have decimal points.
You should be parsing for an int instead of casting as an int.
For example:
if (tipe.equals("anyString")) {
String pot = obj.get("id3");
int x = Integer.parseInt(pot);
ap = new SomeObject(name, x);
}
Since you know that the field is supposed to be an int, you can take advantage of the JSONObject api to handle the parsing for you:
if(tipe.equals("anyString")) {
int pot = obj.getInt("id3");
ap = new SomeObject(name, pot);
}
This is a bit more robust than the casting method -- if somebody changes the json that gets passed to you, the accepted answer might break.
Related
I use a method to get Data from a database and store it in a vector. The method will always return a Vector of Objects where the Object datatype can be either a Date, a Double or a String. In my case, I know that I'm getting a Double, but I want to convert it to an int. is there any easier way than:
System.out.println((int)Double.parseDouble(vector1.get(1).toString()));
Other methods I tried that didn't work:
System.out.println((Integer)vector1.get(1)); // java.lang.ClassCastException: java.lang.Double incompatible with java.lang.Integer
System.out.println((int)vector1.get(1));
Thanks in advance for any constructive response
Following this answer, we can transform the code into
Double d = vector1.get(1);
Integer i = d.intValue();
And I would assume here that if you have some array, maybe you want to transform all of the data there from Double into Integer
vector1.stream().mapToInt(n -> n.intValue()).mapToObj(Integer::new).collect(Collectors.toList());
or
vector1.stream().mapToInt(Double::intValue).mapToObj(Integer::new).collect(Collectors.toList());
You can use intValue() to get int value.
Double b = new Double((double)vector1.get(1));
int value = b.intValue();
You can use Math.round(double) to get the int value. As
Double d = Double.parseDouble(vector1.get(1));
int v = (int) Math.round(d);
Is it possible to determine whether a GSON JsonElement instance is an integer or is it a float?
I'm able to determine whether it's a number:
JsonElement value = ...
boolean isNumber = value.getAsJsonPrimitive().isNumber();
But how to determine if it's an integer or a float, so I can subsequently use the correct conversion method? Either
float f = value.getAsJsonPrimitive().getAsFloat();
or
int i = value.getAsJsonPrimitive().getAsInt();
Edit: The other question may answer why this may be not implemented in GSON, but this question definitely isn't its duplicate.
The only way I've found so far is using regex on a string:
if (value.getAsJsonPrimitive().isNumber()) {
String num = value.getAsString();
boolean isFloat = num.matches("[-+]?[0-9]*\\.[0-9]+");
if (isFloat)
System.out.println("FLOAT");
else
System.out.println("INTEGER");
}
This correctly determines 123 as integer, and both 123.45 and 123.0 as floats.
use something like, and so if return json object is an instance of float or integer you can then apply the required get:
JSONObject jObj = new JSONObject(jString);
Object aObj = jObj.get("a");
if(aObj instanceof Integer){
System.out.println(aObj);
}
I ran into a problem when developing an application that uses Gson to serialize objects and deserialize them. However, I ran into a problem that I cannot explain the cause of and after a while, I narrowed down the problem to this SSCCE:
import com.google.gson.Gson;
/**
* demonstrates the issue at hand
*/
public class Probs {
public Probs () {
//holds the byte array form of the JSON data
byte[] info = new byte[1];
//get the JSON for a data object and store it in the byte array
Gson gson = new Gson();
Data before = new Data(1);
info = gson.toJson(before).getBytes();
//reassemble the JSON data as a string
String json = new String(info);
System.out.println("JSON string: " + json);
//reconstruct the Data object from the JSON data
Data after = gson.fromJson(json, Data.class);
//attempt to get the "num" value and convert it to an integer
Object val = after.getNum();
System.out.println("Class name: " + val.getClass().getName()); //is java.lang.Double (why isn't it java.lang.Object?)
Integer num = (Integer)val; //produces "java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer"
System.out.println("Number: " + num);
}
public static void main(String[] args) {
new Probs();
}
}
/**
* holds the one piece of data
*/
class Data {
Object num;
public Data(int num) {
this.num = num;
System.out.println("Object value: " + this.num);
}
public Object getNum () {
return this.num;
}
}
I did read this post but it did not appear to have any accepted answers. Because of the way I use it in my application, I need to have the Data object store its data as an Object and be able to cast it later to a different type. When I deserialize the data object and call its getNum(), I thought that should return an Object (since that is its return type). In my application, I need to be able to convert that type into an Integer. However, the JVM appears to convert the Object (val) into a Double because the getClass() reveals that it is a Double and not an Object. Then when I try to convert it to an integer via a cast it fails because it is apparently a Double and not an Object.
My question is: why is val a Double and not an Object (what am I not understanding)?
Thank you for your help
The issue is the JSON spec, and what you're doing.
The JSON spec only specifies a single numeric type, which can a include a decimal point and a fractional portion:
2.4. Numbers
The representation of numbers is similar to that used in most
programming languages. A number contains an integer component that
may be prefixed with an optional minus sign, which may be followed by
a fraction part and/or an exponent part.
JSON parsers are left to decide for themselves what to do with that numeric type when parsing/mapping the JSON.
In your case, your Data class has num defined as Object. This gives Gson no hint as to what specific Java numeric type you'd like the JSON numeric type mapped to. The authors of Gson decided to use a Double when this is the case regardless of whether the number in the JSON includes a decimal + fraction or not.
This actually makes perfect sense when you consider that an integer can be expressed as a double, but not the other way around. Using a single type rather than parsing the number and deciding if it's a int or a double provides consistent behavior.
It's unclear why you aren't using Integer (or int) for num in your Data object if that's what you expect/need. You state you need to cast to Integer "later" which means the only thing that object can be in the first place is an Integer; any other casting attempt would fail.
Can someone please explain why you would ever use widening or narrowing conversion? I've read a lot about these but no one ever gives me a practical example. Thanks!
(Java) Widening and Narrowing Conversions have to do with converting between related Types. Take, for example, the relationship between an abstract (super) class and its (child) subclass; let's use the java.lang.Number Class (abstract) and a direct subclass Integer. Here we have:
(superclass) Number
__________/\__________
/ | | \
(concrete subclasses) Integer Long Float Double
Widening Conversion: occurs if we take a specific type (subclass) and attempt to assign it to a less specific type (superclass).
Integer i = new Integer(8);
Number n = i; // this is widening conversion; no need to cast
Narrowing Conversion: occurs when we take a less specific type (superclass) and attempt to assign it to a more specific type (subclass), which requires explicit casting.
Number n = new Integer(5); // again, widening conversion
Integer i = (Integer) n; // narrowing; here we explicitly cast down to the type we want - in this case an Integer
There are certain issues that you need to be aware of such as ClassCastExceptions:
Integer i = new Integer(5);
Double d = new Double(13.3);
Number n;
n = i; // widening conversion - OK
n = d; // also widening conversion - OK
i = (Integer) d; // cannot cast from Double to Integer - ERROR
// remember, current n = d (a Double type value)
i = (Integer) n; // narrowing conversion; appears OK, but will throw ClassCastException at runtime - ERROR
One way to handle this is to use an if statement with the instanceof keyword:
if( n instanceof Integer) {
i = (Integer) n;
}
Why would you want to use this? Let's say you are making a hierarchy of personnel for some program and you have a generic superclass called "Person" which takes a first and last name as parameters, and subclasses "Student", "Teacher", "Secretary", etc.. Here you can initially create a generic person, and assign it (through inheritance) to, say, a Student which would have an additional variable field for studenID set in it's constructor. You can use a single method that takes the more generic (wider) type as a parameter and handle all subclasses of that type as well:
public static void main(String[] args) {
Person p = new Student("John", "Smith", 12345);
printInfo(p);
}
// this method takes the wider Person type as a parameter, though we can send it a narrower type such as Student if we want
public static void printInfo(Person p) {
System.out.println("First: " + p.getFirstName());
System.out.println("Last: " + p.getLastName());
if (p instanceof Student) {
System.out.println( (Student)p).getStudentID() ); // we cast p to Student with Narrow Conversion which allows us to call the getStudentID() method; only after ensuring the p is an instance of Student
}
}
I realize this may not be the ideal way to handle things, but for the sake of demonstration I thought it served to show some of the possibilities.
If some code returns an int containing a true/false value, you could shorten it yourself to a bool which is what it properly represents.
You can also do the opposite.
You can widen a char to int to do some comparisons with ascii values.
You can take an instance of Dog and widen it to IAnimal to pass it to a function.
You can shorten a IAnimal to Dog when you know the type of animal in a List<IAnimal> in a factory or elsewhere for whatever reason.
You use implicit conversions to do math with numerical values of different types. For example, if now() returns a timestamp in seconds as a long:
long t = now()
long nextMinute = t + 60
you have done an implicit widening conversion of 60 (an int) to a long so you can add it to t. Being able to do such conversions makes math much easier to code.
One canonical example of widening and narrowing conversions is how certain file I/O libraries work. Often, a file processing library will have a function / method that reads a single character from a file. If there is a character to read, the function should return that character, and if no characters are left it should return a sentinel value EOF to signal this.
Because any character can appear in a file, typically the function / method would have this signature:
int readCharacter();
Here, the function returns an int that holds a char value if a character was read and which holds EOF as a sentinel otherwise. EOF is typically chosen as an integer that is too big to hold in a char. That way, you can do this:
while (true) {
int ch = readCharacter();
if (ch == EOF) break;
char actualCharValue = (char) ch;
/* process actualCharValue here */
}
Hope this helps!
Take this...
Conversion - Specialized -> Generalized, then it is known as Widening, when you are becoming more general.
Such as Surgeon -> Medico. In this case, you do not need a casting. Because, a surgeon is a Medico by default. So, it is natural that a surgeon can perform all those stuffs that a Medico can do.
While on the other hand,
Conversion - Generalized -> Specialized, then it is known as narrowing, when you are becoming more specialized.
Such as Medico -> Surgeon. Well, in this case, you must have to add casting. Because, a medico can be a surgeon or a physician or a nurse. Think of it, if you ask a nurse to operate on you...
Horrible, right ???
Hope you got the idea.
Example:
Object[] x = new Object[2];
x[0] = 3; // integer
x[1] = "4"; // String
System.out.println(x[0].getClass().getSimpleName()); // prints "Integer"
System.out.println(x[1].getClass().getSimpleName()); // prints "String"
This makes me wonder: the first object element is an instance of class Integer? or is it a primitive data type int? There is a difference, right?
So if I want to determine the type of first element (is it an integer, double, string, etc), how to do that? Do I use x[0].getClass().isInstance()? (if yes, how?), or do I use something else?
There is a difference between int and Integer and only an Integer can go into an Object [] but autoboxing/unboxing makes it hard to pin it down.
Once you put your value in the array, it is converted to Integer and its origins are forgotten. Likewise, if you declare an int [] and put an Integer into it, it is converted into an int on the spot and no trace of it ever having been an Integer is preserved.
not what you asked, but if anyone wants to determine the type of allowed objects in an array:
Oject[] x = ...; // could be Object[], int[], Integer[], String[], Anything[]
Class classT = x.getClass().getComponentType();
x is an object array - so it can't contain primitives, only objects, and therefore the first element is of type Integer. It becomes an Integer by autoboxing, as #biziclop said
To check the type of a variable, use instanceof:
if (x[0] instanceof Integer)
System.out.println(x[0] + " is of type Integer")
You want to use the instanceof operator.
for instance:
if(x[0] instanceof Integer) {
Integer anInt = (Integer)x[0];
// do this
} else if(x[0] instanceof String) {
String aString = (String)x[0];
//do this
}