13 Replies Latest reply: Jun 18, 2010 5:39 AM by 800268 RSS

    Convert String to generic type

      I have a class that uses Generic Types. The types are either String, Double, Integer, or possibly some other user defined type. I would like to read a text file and cast into the appropriate type. However, I get a class cast exception when the type is Double. Here is an example that recreates the problem. How can I actually convert the text file into the appropriate type?

      public class TestClass<T> {
          T value = null;
          public TestClass(){
          public void parse(String text){
                  value = (T)text;
              }catch(ClassCastException ex){
          public T getValue(){
              return value;
          public static void main( String args[] ){
              TestClass<Double> myDouble = new TestClass<Double>();
              String myValue = "123.456";
              myDouble.parse(myValue);//no problem here, not sure why
              System.out.println(2.0*myDouble.getValue());//exception thrown here
        • 1. Re: Convert String to generic type
          Casting won't magically convert an object of one type into an object of some random other type and using generics won't change that.
          The compile warning should have been a clue that something could go wrong.

          You probably want to use some implemenation of java.text.NumberFormat.
          • 2. Re: Convert String to generic type
            I realize that this is just a test, but I'd argue that a type whose purpose is to wrap a number, shouldn't be created with no value set.

            I think you might be better off either creating a factory that creates Number subclasses, or just using BigDecimal (which already knows how to parse a string) for everything.
            • 3. Re: Convert String to generic type
              Yes, it is just a test class that illustrates the problem. I am creating a command parsing library similar to JArgs but more current and more useful for my particular application. In my application commands are not passed at the command line. Rather, the commands will be in text files. In my command parsing library, I want to have the same functionality regardless of whether arguments are String, Double, or Integers. I want to avoid redundancy just to accommodate the data type. It seems like Generic Types are the way to go, but the problem is in parsing the text file. I need to keep Strings as Strings when the type is String. I need Double.parseDouble(text) when the type is Double and so forth. The test class in my original post simply illustrates the problem.
              • 4. Re: Convert String to generic type
                 myDouble.parse(myValue);//no problem here, not sure why
                        System.out.println(2.0*myDouble.getValue());//exception thrown here
                It does not cause an exception because generics are erased at compile time (mostly for backwards compatibility).
                After the compile it it's equivalent to the following, with only a cast at the second statement so that's where you can the exception.
                // after erasure
                public class TestClass {
                  Object value = null;
                  public void parse(String text){
                            value = text;
                    public Object getValue(){
                        return value;
                    public static void main( String args[] ){
                        TestClass myDouble = new TestClass();
                        String myValue = "123.456";
                        // CCE because getValue returns a String
                        System.out.println(2.0 * (Double) myDouble.getValue());
                • 5. Re: Convert String to generic type
                  Fine, but I don't see what you're hoping to accomplish with this wrapper class or generics here. At some point you're going to have to identify what the type is of the value represented by the string. Then you're going to turn it into the specific type. Once you know the specific type, the generic wrapper doesn't buy you anything. Before you know the specific type, you can't use generic wrapper (since you don't know what type to create it with).

                  Again, it sounds to me like a factory is the solution.
                  • 6. Re: Convert String to generic type
                    Here are two of the interfaces in my library. The first one is the most general. I extend this interface for specific types of arguments. It is the parse method in this interface that should be implemented to read and process a text file.
                    public interface Argument <T>{
                        public String getName();
                        public String getDescription();
                        public boolean isRequired();
                        public void isRequired(boolean required);
                        public boolean hasValue();
                        public String getHelpText();
                        public boolean parse(String line)throws ArgumentException;
                        public String paste() throws ArgumentException;
                    This second bit of code shows and example of how I extended the interface for a specific type of argument. I am trying to create the library so that I don't have to create redundant code just to accomodate the type. For example, I'm trying to use Generic Types so that I can just use Generic Type get, set and add methods as shown below as opposed to having to do addDouble(), addInteger(), getDouble, getInteger(), and so on.

                    By the way, the class that uses this interface will process text in the form of dimensions=(width@400 height@500); The width and height arguments are the named arguments referenced in the methods below. The 400 and 500 are the values.

                    Ideally, there would be a T.parseAs<T>(String) method like there is a Double.parseDouble(String).
                    public interface UserProvidedNamedValues<T> extends Argument<T>{
                        public int getNumberOfValues();
                        public boolean hasValue();
                        public void addValueAtNamedIndex(String indexName, T arg)throws ArgumentException;
                        public void removeValueAtNamedIndex(String indexName)throws ArgumentException;
                        public void setValueAtNamedIndex(String indexName, T arg);
                        public T getValueAtNamedIndex(String indexName)throws ArgumentException;
                        public TreeMap<String, T> getAllValues()throws ArgumentException;
                    • 7. Re: Convert String to generic type
                      So, UserProvidedNamedValues represents that set of key/value pairs? Is T the type of the value then -- and if so, does that mean that in any set of key/value pairs, the types of the values are always the same?

                      Anyway... what what point do you determine what T is? Can't you do the parsing there? For that matter... aren't you doing parsing there already?

                      My gut sense here is that you're not going to gain much code reuse here by use of generics, at least not in the parsing step.
                      • 8. Re: Convert String to generic type
                        Yes, the T defines the type in a set of key/value pairs. All types are the same within each instance of the class. My main application is a statistics program that runs a variety of statistical procedures. I am creating this argument processing library so that I can easily define the commands needed to define different types of statistical analysis. Within my statistics application I have a command class like the following:
                        groupLayout = new ArgumentSelectOneValue<String>("layout", "Group layout", false);
                        groupLayout.addValue("stacked", "Stacked group layout", false);
                        groupLayout.addValue("layered", "Layered group layout", false);
                        groupLayout.addValue("sidebyside", "Side-by-side group layout", true);
                        yAxis = new ArgumentSelectOneValue<String>("yaxis", "Y-axis scale", false);
                        yAxis.addValue("freq", "Show frequency on y-axis", false);
                        yAxis.addValue("density", "Show density on y-axis", true);
                         trellis = new ArgumentUserProvidedValues<Integer>("trellis", "Trellis layout by Rows and Columns", false, 2);
                         trellis.addValueAtNamedIndex("rows", 1);
                         trellis.addValueAtNamedIndex("cols", 1);
                         dimensions = new ArgumentUserProvidedValues<Integer>("dimensions", "Chart dimensions", false, 2);
                         dimensions.addValueAtNamedIndex("width", 450);
                         dimensions.addValueAtNamedIndex("height", 400);
                        The ArgumentUserProvidedValues class implements the interface listed previously. A person using the statistics application will create text files like this:

                        graph{ layout=stacked; yaxis=freq; trellis=(rows@1 cols@1); dimensions=(width@400 height@500) }

                        This should be read by the command class, parsed, and to tell the statistics application what to do. My goal is minimal code with maximal reuse, but maybe that's not possible.
                        • 9. Re: Convert String to generic type
                          Here's my point: you have parse as an instance method of Argument, but by the time you instantiate an Argument implementation, you've already determined that the value is a String (and thus, you've done some degree of parsing on it). In fact you seem to already have parsed it and passed it via an addValue method.

                          It would probably make more sense to move parse() completely out of Argument, and stick it in whatever instantiates Argument implementations. It's not clear to me why you feel it needs to be in Argument at all.
                          • 10. Re: Convert String to generic type
                            Yes, that makes perfect sense and it will get me around the Generic Type issue.

                            • 11. Re: Convert String to generic type
                              My problem was solved, but the original question still remains.
                              • 12. Re: Convert String to generic type
                                Whatever that was.
                                • 13. Re: Convert String to generic type
                                  psychostat wrote:
                                  How can I actually convert the text file into the appropriate type?
                                  My problem was solved, but the original question still remains.
                                  Only way is to try and see what works, starting from the most restrictive type. First try to parse as int, then as double, then a boolean and if all fails just keep it as String.
                                  But since you seems to know the expected type (yAxis=enum of possible values, dimension=int width, int height) you could only try to parse the expected type and just throw an exception if it fails.

                                  How to implement that isn't really clear to me how you are using the Argument class to parse a text file, but I guess you want something like.
                                  class AbstractUserArgument<T> implements UserProvidedNamedValues<T> {
                                    private Map<String, T> optionValues;
                                    protected abstract T parseOption(String text) throws Exception;
                                    public void parse(String allOptions) throws ArgumentException {
                                      for(String option : splitOptions(allOptions) {
                                        String optionName, optionValue = splitOption(option); // pseudo code ;-)
                                        try {
                                          setValueAtNamedIndex(optionName, parseOption(optionValue));
                                        catch(Exception e) {
                                          throw new ArgumentException(e, "Invalid argument for "
                                                           + getName() + " for " + optionName);
                                  class IntegerArgument extend AbstractUserArgument<Integer> {
                                    protected Integer parseOption(String text) throws Exception {
                                        return Integer.parseInt(text);
                                  Note that that assumes your 'an argument has only options of the same type' restriction. Argument doesn't need to be generic (it doesn't use it).