How to use Java Generics to save T from String

I am trying to use Java generics for my specific use case. There is a generic class Node, and in this example there will be many implementing class types NodeBoolean.

public abstract class Node<T>
    {
        T defaultValue;

        public Node(T defaultValue) {
            this.defaultValue = defaultValue;
        }

        protected abstract T parse(String input) ;
        public T getValue()
        {
            try
            {
                // here will be some logic to get String value from some db or any other source
                String input = "true";
                return parse(input);
            } catch (Exception e) {
                return defaultValue;
            }
        }
    }

Class implementation

class NodeBoolean extends Node<Boolean>
{
    public NodeBoolean(Boolean defaultValue) {
        super(defaultValue);
    }

    @Override
    protected Boolean parse(String input) {
        return Boolean.parseBoolean(input);
    }
}

Testing class

class TestNode
{
    public static void main(String[] args) {
        NodeBoolean node =  new NodeBoolean(true);
        System.out.println(node.getValue());
    }
}

Problems I encounter with this approach

  • Suppose that there are several options for a class constructor Node, then all implementation classes also need to define them for visibility. This problem can be solved using the Builder pattern, but I just wonder about other possible solutions.

  • , parse. instanceof of defaultValue Node. Node abstract.

  • , parse, String T Node. , Node, - .

, 3 . , - , .

+4
2
  • , builder factory - . .

  • , parse , node, ?


public class Node<T> {
    private T defaultValue;
    private Function<String, T> parser;

    public Node(T defaultValue,
                Function<String, T> parser) {
        this.defaultValue = defaultValue;
        this.parser = parser;
    }

    public T getValue()
    {
        // depending on the parser, re-parsing every time this is called could get expensive!
        try
        {
            // here will be some logic to get String value from some db or any other source
            String input = "true";
            return parser.apply(input);
        } catch (Exception e) {
            return defaultValue;
        }
    }
}

node,

Node<Boolean> node = new Node<>(s -> Boolean.parseBoolean(s))

, node - .

  1. . 2.

Java 8 Function lambdas , Java 1.0, .

public interface Function<I, O> {
    O apply(I);
}

- , .. - , .

Node<Boolean> node = new Node<>(new Function<String, Boolean>() {
    public Boolean apply(String s) {
        return Boolean.parseBoolean(s);
    }
});

2

.

public class NodeFactory {
    private static final Function <String, Boolean> BOOLEAN_PARSER = s -> Boolean.parseBoolean(s);
    .// plus more for integers, double, etc, as required

    private NodeFactory() {
        // no-op
    } 

    public static Node<Boolean> booleanNode(boolean defaultValue){
        return new Node<Boolean>(defaultValue,
                                 BOOLEAN_PARSER);
    }

    // plus more for integer, double, etc, as required
}

public class BooleanNode extends Node<Boolean> {
    public BooleanNode(boolean defaultValue) {
        super(defaultValue,
              s -> Boolean.parseBoolean(s)); // or use a static parser as in the factory example
    }
}

Node - , .

+3

Node? ? " "

Node<Boolean> booleanNode = new Node<Boolean>(true) {
    @Override
    protected Boolean parse(String input) {
        return Boolean.parseBoolean(input);
    }
};

, , Factory, Node:

class NodeFactory {
    public <T> static createNode(Class<T> classType) {
        if (classType == Boolean.class) {
            return newBooleanNode();
        } else if (classType == Integer.class){
            return newIntegerNode();
        }
    } 

    private Node<Boolean> newBooleanNode() {
        return new Node<Boolean>(true) {
            @Override
            protected Boolean parse(String input) {
                return Boolean.parseBoolean(input);
            }
        }
    }

    private Node<Integer> newIntegerNode() {
        return new Node<Integer>(0) {
            @Override
            protected Boolean parse(String input) {
                return Integer.parseInt(input);
            }
        }
    }
}

Node<Boolean> booleanNode = NodeFactory.createNode(Boolean.class);
Node<Integer> integerNode = NodeFactory.createNode(Integer.class);
0

All Articles