JAVA: String for a (dynamically known) primitive type to instantiate a (dynamically known) class

I have a repository class that uses text files (requirement), which means I have to read lines and do them to create objects. The problem is that I want my repository class to be generic, how can I do this to use it to manage different types of objects.

So, is there a (more elegant) way to dynamically translate strings to any type (primitive) type that it needs at run time, while avoiding a lot of try-catch structures with multiple ifs / switch?

As a short simplified version, I want objectA.txt to contain only objectA information, similarly for objectB.txt and my repository code to handle both:

Repository repo A = new repository ("objectA.txt", <type list for A>); Type A a = repoA.getOne ();

Repo repository B = new repository ("objectB.txt", <type list for B>); Type B b = repoB.getOne ();

What I have:

public class FileRepository extends InMemoryRepository{
    private String fileName;
    private List<Class> types;

    public FileRepository(String fileName, List<Class> types) {
        //@param types 
        //     - list containing the Class to be instantiated followed by it field types
        super();
        this.fileName = fileName;
        this.types=types;
        loadData();
    }

    private void loadData() {
        Path path = Paths.get(fileName);

        try {
            Files.lines(path).forEach(line -> {
                List<String> items = Arrays.asList(line.split(","));

                //create Class array for calling the correct constructor
                Class[] cls=new Class[types.size()-1];
                for (int i=1; i<types.size(); i++){
                    cls[i-1]=types.get(i);
                }

                Constructor constr=null;
                try {
                    //get the needed constructor
                    constr = types.get(0).getConstructor(cls);
                } catch (NoSuchMethodException e) {
                    //do something
                    e.printStackTrace();
                }
                //here is where the fun begins
                //@arg0 ... @argn are the primitives that need to be casted from string 
                //something like: 
                //*(type.get(1))* arg0=*(cast to types.get(1))* items.get(0);
                //*(type.get(2))* arg1=*(cast to types.get(2))* items.get(1);
                //...

                Object obj= (Object) constr.newInstance(@arg0 ... @argn);

            });
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

PS: I am new to JAVA, so please keep the explanations as simple as possible.

+4
source share
3 answers

There is no IDE at hand, so I hope this makes sense:

private static final Map<Class, Function<String, ? extends Object>> parsers = new HashMap<>();

static {
  parsers.put(Long.class, Long::parseLong);
  parsers.put(Integer.class, Integer::parseInt);
  parsers.put(String.class, String::toString);
  parsers.put(Double.class, Double::parseDouble);
  parsers.put(Float.class, Float::parseFloat);
  // add your own types here.
}

public <T> T parse(Class<T> klass, String value) {
  // add some null-handling logic here? and empty values.
  return (T)parsers.get(klass).apply(value);
}

, :

parameters =
     IntStream
     .range(0, cls.size-1)
     .map(i -> (Object)parse(types.get(i), items.get(i)))
     .toArray(Object[]::new);
+1

, - -unboxing , - valueOf, String (wrapper), .

, :

import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Consumer;

/**
 * Created by kmhaswade on 3/18/16.
 */
//@ThreadUnsafe
public class NonStreamingGenericPrimitiveDataRepo<T> implements Iterable<T> {

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            @Override
            public boolean hasNext() {
                return theIterator.hasNext();
            }

            @Override
            public T next() {
                String next = theIterator.next();
                try {
                    Method m = theType.getDeclaredMethod("valueOf", String.class);
                    return (T) m.invoke(null, next);
                } catch (NoSuchMethodException | IllegalAccessException e) {
                    throw new RuntimeException("This is impossible!");
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("data: " + next + " does not represent type: " + theType);
                }
            }
        };
    }

    @Override
    public void forEach(Consumer<? super T> action) {
        throw new RuntimeException("left as an exercise :-) ");
    }
    private final ArrayList<String> theCache;
    private final Iterator<String> theIterator;
    private final Class<T> theType;
    public NonStreamingGenericPrimitiveDataRepo(Reader reader, Class<T> theType) throws IOException {
        Objects.requireNonNull(reader);
        Objects.requireNonNull(theType);
        if (Integer.class.equals(theType)
                || Long.class.equals(theType)
                || Float.class.equals(theType)
                || Double.class.equals(theType)
                || Boolean.class.equals(theType)
                || String.class.equals(theType)) {
            theCache = new ArrayList<>();
            try (BufferedReader br = new BufferedReader(reader)) {
                String line;
                while ((line = br.readLine()) != null)
                    theCache.add(line);
            }
            theIterator = theCache.iterator();
            this.theType = theType;
        } else {
            throw new IllegalArgumentException("Not a wrapper type: " + theType);
        }
    }

    public static void main(String[] args) throws IOException {
        for (int i : new NonStreamingGenericPrimitiveDataRepo<>(ints(), Integer.class))
            System.out.println("read an int: " + i);
        for (float f : new NonStreamingGenericPrimitiveDataRepo<>(floats(), Float.class))
            System.out.println("read a float: " + f);
        for (boolean b: new NonStreamingGenericPrimitiveDataRepo<>(booleans(), Boolean.class))
            System.out.println("read a boolean: " + b);
    }
    static StringReader ints() {
        return new StringReader("1.w\n2\n-3\n4\n");
    }
    static StringReader floats() {
        return new StringReader("1.0f\n3.25f\n-3.33f\n4.44f\n");
    }
    static StringReader booleans() {
        return new StringReader("false \ntrue\n");
    }
}
0

String, :

public class Test {

    final static String LONG_PATTERN = "[-+]?\\d+";
    final static String DOUBLE_PATTERN = "[-+]?(\\d*[.])?\\d+";
    final static String BOOLEAN_PATTERN = "(true|false)";
    final static String CHAR_PATTERN = "[abcdefghijklmnopqrstuvwxyz]";

    public static void main(String[] args) {

        String[] xList= {
                "1", //int 
                "111111111111", //long 
                "1.1", //float
                "1111111111111111111111111111111111111111111111111111.1", //double
                "c", //char
                "true", //boolean
                "end" //String
                };

        for (String x: xList){

            if(x.matches(LONG_PATTERN)){
                long temp = Long.parseLong(x);
                if (temp >= Integer.MIN_VALUE && temp <= Integer.MAX_VALUE){
                    System.out.println( x + " is int use downcast");
                } else {
                    System.out.println( x + " is long");
                }
            } else if(x.matches(DOUBLE_PATTERN)){
                double temp = Double.parseDouble(x);
                if (temp >= Float.MIN_VALUE && temp <= Float.MAX_VALUE){
                    System.out.println( x + " is float use downcast");
                } else {
                    System.out.println( x + " is Double");
                }
            } else if (x.toLowerCase().matches(BOOLEAN_PATTERN)){
                boolean temp = x.toLowerCase().equals("true");
                System.out.println(x + " is Boolean");
            } else if(x.length() == 1){
                System.out.println(x + " is char");
            }else {
                System.out.println( x + " is String");
            }
        }

    }
}

:

1 is int use downcast
111111111111 is long
1.1 is float use downcast
1111111111111111111111111111111111111111111111111111.1 is Double
c is char
true is Boolean
end is String

4 , double, boolean, String. java, :

Integers
    byte
    char (represented as a character)
    short
    int
    long
Floating point numbers
    float
    double
Boolean
    boolean

This way you can determine the types that your string is in. You can change the code to check the range and type by entering numbers in bytes and shorts, respectively.

0
source

All Articles