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.
Related
I am writing a compiler, that reads from an input file, parses it and creates various kind of tokens. Further, in parsing, upon getting a NumLitToken , I retrieve its's number value stored as String and want to save it as a Number for further stages of transformations.
I am not aware whether the String contains int/ float / long / double etc. so i am using NumberFormat.getInstance().parse(x) method and expecting appropriate casted value, but i don't know why i am not getting a cast to Integer for int values.
Also, if there is any other way better to cast to Number from String, please enlighten me about it.
A small extract:
import java.text.*;
public class Main
{
public static void main(String[] args) throws ParseException{
String x = "100";
Number o = NumberFormat.getInstance().parse(x);
System.out.println(o.getClass().toString());
if(o instanceof Integer){
System.out.println("int");
}
}
}
Output:
class java.lang.Long
UPDATE : Turns out, the method only returns long or double. What to do to get appropriate cast to Number ? Is there a better way rather than trying to cast for every number type?
Because the docs say so:
Returns a Long is possible, otherwise a Double
Simple as that.
If you're just trying to parse an int, int x = Integer.parseInt("500"); does the job!
As mentioned in a different answer it is how it works.
If you want to a function that returns the most appropriate type depending its size the apache-commons NumberUtils.createNumber will do that for you.
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.
I am facing the below problem:
I will be getting values similar or of greater length compared to temp value :
public class NumberFormat {
public static void main(String arg[]){
Integer numValue = null;
String temp="5474151538110135";
numValue=Integer
.parseInt(temp.trim());
System.out.println("--> "+numValue);
}
}
Please provide a solution.
Exception in thread "main" java.lang.NumberFormatException: For input string: "5474151538110135"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:60)
at java.lang.Integer.parseInt(Integer.java:473)
at java.lang.Integer.parseInt(Integer.java:511)
at com.filetransfer.August.NumberFormat.main(NumberFormat.java:10)
5474151538110135 is greater than Integer.MAX_VALUE. Use Long.parseLong instead or BigInteger if the input number is likely to grow significantly
Long numValue = Long.parseLong(temp.trim());
Probably beacuse the value is larger than max int value which is 2147483647.
System.out.println(Integer.MAX_VALUE);
You should parse it to Long which max value is 9223372036854775807.
System.out.println(Long.MAX_VALUE);
like this
Long numValue = null;
String temp="5474151538110135";
numValue=Long
.parseLong(temp.trim());
I would recommend use BigInteger for avoiding errors
Advantage of BigInteger Class
Integer is a wrapper of the primitive type int.The wrapper classes are basically used in cases where you want to treat the primitive as an object for ex-trying to pass an int value in a method that would take only a type of Object in such a case you would want to wrap primitive int value in the wrapper Integer which is of type Object. To know specific advantages of Integer I would suggest you to take a look at the Integer api provided by Sun.
Now coming to the BigInteger, you would use it in calculations which deal with very large numbers.The use of BigIntegers is in Security where typically it is used for keys specifications.For more info on BigIntegers take a look at the following link http://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
I hope the info helped you.
I need a way to return the type of an object (as a string, or class of the object, whichever is easier) given a string with the value in it.
I could parse it with each of the types I want, but there are problems associated with that (such as an int may also be parsed as a long, a float can be parsed as a double). Here's my sketch:
private String typeOf(String test) {
if (test == "true" || test == "false")
return "boolean";
else if (// its a number)
// figure out a way to parse all number types?
// return corresponding type
else
// can't be parsed with any boolean or number types... just a string
return "string";
}
The types I am checking are: String, long, int, short, byte, byte[], float, and double.
Remember I need the SPECIFIC type in order to accomplish the make-or-break functionality of this program. Any help is appreciated.
I'm trying to make a Named Binary Tag (specifications here) that holds a specific type of data given by user input (a JOptionPane - input dialog). In order to make the correct type of tag, I need to know the type of the data given. (Is there a way to get the input from the user where I can avoid the String problem entirely?) Having a String to work with in the first place has become the main source of my issue.
To start your String checking is incorrect. Aside from that think about the different datatypes and their possible values.
An int or Integer's possibles values all lie within the ranges of a long. The same is true for Floats and Doubles. You will need to figure out which Datatype's ranges are subsets of which and test in that order. As an example here is a quick snippit for testing for Integers and Longs.
private String typeOf(String suppliedTest) {
String test = suppliedTest.strip().toLower();
if (test.equals("true") || test.equals("false"))
return "boolean";
try {
int testInt = Integer.parseInt(test);
return "integer";
} catch (NumberFormatException e) {}
try {
long testLong = Long.parseLong(test);
return "long";
catch (NumberFormatException e) {}
...
}
You can use class specific parsing methods to check, if a String represents a certain type, such as
Double.parseDouble()
Integer.parseInt()
these methods will throw NumberFormatException if the input string does not contain a value, that represents the appropriate type.
You don't have enough different to know the difference. All you can do is find the smallest type when can represent that data. a 0 could be a String, long, int, short, byte, float or double. You will need to decide which would be the most appropriate response.
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.