I have the following class with methods marked as unchecked that give me a warning. They compile/work fine but I am interested if there is a way to generify the class as IntelliJ IDEA is offering me (but unable to do) to remove the warnings.
public abstract class Attribute {
private final AttributedNode containerNode;
private boolean computationComplete;
public Attribute(AttributedNode node) {
this.containerNode = node;
this.computationComplete = false;
}
public AttributedNode getContainerNode() {
return containerNode;
}
public Attribute getAttributeFromChildNode(int childIndex, AttributeNameEnum attributeName) {
AttributedNode node = getContainerNode().getChild(childIndex);
return node.getAttribute(attributeName);
}
public String getChildNodeText(int index) {
return getContainerNode().getChild(index).getText();
}
#SuppressWarnings("unchecked")
public <T, E extends Attribute> List<T> getListOfChildAttributeValues(AttributeNameEnum name) {
List<T> result = new LinkedList<>();
for (AttributedNode node : this.getContainerNode().getChildren()) {
E attribute = (E) node.getAttribute(name);
result.add((T) attribute.getValue());
}
return result;
}
public <T extends Attribute> Object getAttributeValueFromContainer(AttributeNameEnum name) {
return this.<T>getAttributeValueFromNode(name, this.getContainerNode());
}
public <T extends Attribute> Object getAttributeValueFromParent(AttributeNameEnum name) {
return this.<T>getAttributeValueFromNode(name, this.getContainerNode().getParent());
}
#SuppressWarnings("unchecked")
public <T extends Attribute> Object getAttributeValueFromNode(AttributeNameEnum name, AttributedNode node) {
T attribute = (T) node.getAttribute(name);
return attribute.getValue();
}
// other methods eluded
P.S. I apologize ahead of time of maybe my lack of understanding Generics.
Related
I have a Java class with a property that can be either a String, a boolean or a List.
What would be the best approach to declare that property type? Knowing that I can only know its type at Runtime.
My first approach was to define that property with type Object, but not sure if there's a better way to achieve this.
private final String expression;
private Object expressionValue;
ParsedExpression(String expression, Person person) {
this.expression= expression;
expressionEvaluator(person);
}
private void expressionEvaluator(Person person) {
switch (this.expression) {
case "name":
expressionValue = person.getName();
break;
case "adult":
expressionValue = person.isAdult();
break;
case "addresses":
expressionValue = person.getAddresses();
break;
default:
throw new RuntimeException("Property does not exist on type Person");
}
}
If you have a very few types and not going to change them you can use a generic class with a private constructor and a few factory methods which allow creating an instance only with specified type parameters:
public final class ExpressionValue<T> {
private final T value;
private ExpressionValue(T value) {this.value = value;}
public Optional<String> getAsString() {
return (value instanceof String) ? Optional.of((String)value) : Optional.empty();
}
public Optional<Boolean> getAsBoolean() {
return (value instanceof Boolean) ? Optional.of((Boolean) value) : Optional.empty();
}
// in this context empty collection and empty optional mean different things
#SuppressWarnings("OptionalContainsCollection")
public Optional<List<?>> getAsList() {
return (value instanceof List) ? Optional.of((List<?>) value) : Optional.empty();
}
public void use(Consumer<? super String> stringUser, Consumer<? super Boolean> booleanUser, Consumer<? super List<?>> listUser) {
getAsString().ifPresent(stringUser);
getAsBoolean().ifPresent(booleanUser);
getAsList().ifPresent(listUser);
}
public static ExpressionValue<String> fromString(String string) {
return new ExpressionValue<>(string);
}
public static ExpressionValue<Boolean> fromBoolean(boolean bool) {
return new ExpressionValue<>(bool);
}
public static ExpressionValue<List<?>> fromList(List<?> list) {
return new ExpressionValue<>(list);
}
}
If you have many available types or need more flexibility of types you can use a hierarchical approach. In this case, you need to create an interface with common String, boolean and List methods, and then create implementations of this interface with all available type parameters. It may look like this:
public interface ExpressionValue<T> {
boolean check();
}
public abstract class ExpressionValueSkeleton<T> implements ExpressionValue<T> {
private T value;
public ExpressionValueSkeleton(T value) {
this.value = value;
}
protected T getValue() {
return value;
}
}
public class StringExpressionValue extends ExpressionValueSkeleton<String> {
public StringExpressionValue(String value) {
super(value);
}
#Override
public boolean check() {
return !getValue().isEmpty();
}
}
public class BooleanExpressionValue extends ExpressionValueSkeleton<Boolean> {
public BooleanExpressionValue(Boolean value) {
super(value);
}
#Override
public boolean check() {
return getValue();
}
}
public class ListExpressionValue<E> extends ExpressionValueSkeleton<List<E>> {
public ListExpressionValue(List<E> value) {
super(value);
}
#Override
public boolean check() {
return !getValue().isEmpty();
}
}
If you want perform some operations which are available only for some types you can use Acyclic Visitor pattern.
I have an interface:
public interface ITransformer<S,T>{
public void transform(S source,T target);
default String getTransformerName(){
Class<S> s;
Class<T> t;
return s.getName() + t.getName(); //*********
}
}
the error message the starred line:
The local variable s may not have been initialized
The local variable t may not have been initialized
I would like to use this method to return a string with [S.classname][T.classname] . Please let me know how to achieve this or is this impossible to do at interface ?
Update: Jan 12
My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows:
public interface ITransformer<S,T>{
public void transform(S source,T target);
public FieldEntry<S, T> getTransformerName();
}
public class FieldEntry<S,T> implements Comparable<FieldEntry> {
private Class<S> s;
private Class<T> t;
public FieldEntry(Class<S> s,Class<T> t){
this.s = s;
this.t = t;
}
public String getEntryName(){
return s.getName() + t.getName();
}
#Override
public int compareTo(FieldEntry entry) {
if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");
return entry.getEntryName().compareTo(this.getEntryName());
}
}
In order to demonstrate why this can’t work, you may change your class to
public interface ITransformer<S,T>{
public void transform(S source,T target);
static <In,Out> ITransformer<In,Out> noOp() {
return (source,target) -> {};
}
static void main(String... arg) {
ITransformer<String,Integer> t1 = noOp();
ITransformer<Long,Thread> t2 = noOp();
System.out.println(t1 == (Object)t2);
}
}
Running this will print true. In other words, both functions are represented by the same instances, so there can’t be and property allowing to recognize their different type.
Generally, when two functions (lambda expressions or method references) exhibit the same behavior, a JVM may represent them by the same implementation type or even the same instance.
Even for non-interface classes, this doesn’t work due to Type Erasure. It only works when you have a reifiable (i.e. non-generic) type extending or implementing a generic type.
It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it:
public interface ITransformer<S, T> {
public void transform(S source, T target);
default String getTransformerName() {
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = null;
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType paramInterface = (ParameterizedType) genericInterface;
if (paramInterface.getRawType().equals(ITransformer.class)) {
parameterizedType = paramInterface;
break;
}
}
}
if (parameterizedType == null) {
throw new IllegalStateException("!");
}
return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();
}
}
public class StringToIntegerTransfomer implements ITransformer<String, Integer> {
#Override
public void transform(String source, Integer target) {
}
}
public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {
}
public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
#Override
public void transform(String source, Long target) {
}
}
#Test
public void test() {
ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {
#Override
public void transform(String source, String target) {
}
};
ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {
#Override
public void transform(String source, Double target) {
}
};
System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}
Output for this snippet:
intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String
java.lang.IllegalStateException: !
This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>(). But you can improve this code.
Better option is to use some base implementation of interface and pass source and target classes into constructor:
public interface ITransformer<S, T> {
void transform(S source, T target);
String getTransformerName();
}
public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {
private final Class<S> sourceClass;
private final Class<T> targetClass;
public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
this.sourceClass = sourceClass;
this.targetClass = targetClass;
}
public String getTransformerName() {
return sourceClass.getName() + targetClass.getName();
}
}
In Java it is impossible to get a Class<S>, unless you already know which class S is, or something else that knows which class S is gives you one.
I'm using Guava's LineProcessor interface when reading lines from files. I've created my class called Line Loader which will store lines read. I want it to be generic on choice of collection lines should be stored in so I wrote something like this:
public abstract class LineLoader<T> implements LineProcessor<Collection<T>> {
private final Collection<T> result;
public LineLoader() {
this.result = init();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public Collection<T> getResult() {
return result;
}
protected abstract Collection<T> init();
}
where with init() method I force subclasses to chose type of collection, for example:
public abstract class LinkedLineLoader<T> extends LineLoader<T> {
#Override
protected Collection<T> init() {
return new LinkedList<T>();
}
}
I planned on doing this:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>> {
private final C<T> result;
public LineLoader() {
result = new C<T>();
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws Exception {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C<T> getResult() {
return result;
}
}
so that latter subclases (if needed) could do:
public class LinkedLineLoader<T> extends LineLoader<LinkedList<T>> {
}
but it's not possible. Is there a clean solution to this problem?
In Java it is not possible to create instances from generic type arguments, because generics are erased at run-time. Also, generic type arguments can not themselves declare additional type arguments like C<T>. Therefore the code you posted is entirely illegal and will not compile:
private final C<T> result; // illegal
result = new C<T>(); // illegal
Aside from that, your declaration of the type arguments itself has some flaws. The following code is no legal Java code:
public class LineLoader<T> implements LineProcessor<C<T> extends Collection<T>>
It should actually look e.g. like this:
public class LineLoader<T, C extends Collection<T>> implements LineProcessor<C>
As a solution to your problem, you could declare your LineLoader as shown above, and add a protected constructor, that takes the generic collection as an argument:
public abstract class LineLoader<T, C extends Collection<T>> implements LineProcessor<C> {
private final C result;
protected LineLoader(C collection) {
result = collection;
}
protected boolean add(final T line) {
return result.add(line);
}
#Override
public boolean processLine(final String line) throws IOException {
final T data = parser.parseLine(line);
if (data == null) {
return false;
}
return add(data);
}
#Override
public C getResult() {
return result;
}
}
Then you can implement your LinkedLineLoader like so:
class LinkedLineLoader<T> extends LineLoader<T, LinkedList<T>> {
public LinkedLineLoader() {
super(new LinkedList<>());
}
}
I am trying to implement a class representing an XML tree as follows:
public class XML<T extends XML<T>> {
private final List<MarkupLanguage> nodeList = new ArrayList<>();
private final Map<String, String> attributeList = new HashMap<>();
public T attr(final String key, final String value) {
if (value != null) {
this.attributeList.put(key, value);
}
return (T) this;
}
public T appendTo(final T node) {
node.add(this);
return (T) this;
}
...
}
My problem is typing of these clauses - I am getting unchecked cast for "return (T) this;"
and also when I try to use the XML class by itself:
final XML url = new XML("url");
new XML("loc")
.add("http://goout.cz")
.appendTo(url);
I am getting:
Unchecked cast to call appendTo(T) as a member of raw type XML.
How can I improve my code to get better typing?
Just type it:
final XML<T> url = new XML<T>("url");
new XML<T>("loc")
.add("http://goout.cz")
.appendTo(url);
It also looks like you really want to use XML<T> for your methods, not T, so you can avoid the casts (but I could be wrong):
public XML<T> attr(String key, String value) {
if (value != null) {
this.attributeList.put(key, value);
}
return this;
}
public XML<T> appendTo(XML<T> node) {
node.add(this);
return this;
}
What about the approach below (simple inheritance plus generic methods):
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class XmlTest {
#Test
public void test() {
XMLFirstSubclass url = new XMLFirstSubclass("url");
XMLSecondSubclass xmlSecondSubclassInstance = new XMLSecondSubclass(
"loc").add("http://goout.cz").appendTo(url);
}
}
abstract class XML {
private final List<String> texts = new ArrayList<String>();
private final List<XML> nodes = new ArrayList<XML>();
private final String nodeName;
protected XML(String nodeName) {
this.nodeName = nodeName;
}
#SuppressWarnings("unchecked")
public <R extends XML> R add(String text) {
texts.add(text);
return (R) this;
}
#SuppressWarnings("unchecked")
public <R extends XML, T extends XML> R add(T node) {
nodes.add(node);
return (R) this;
}
#SuppressWarnings("unchecked")
public <R extends XML, T extends XML> R appendTo(T node) {
node.add(this);
return (R) this;
}
}
class XMLFirstSubclass extends XML {
public XMLFirstSubclass(String nodeName) {
super(nodeName);
}
}
class XMLSecondSubclass extends XML {
public XMLSecondSubclass(String nodeName) {
super(nodeName);
}
}
Note that the generic methods allow to get a node from one type T and return the instance's type R, which can be different than the argument's type. T can be different than R, but both inherit XML.
Comments about the approach presented in the question
The approach that you're using until now can lead to strange situtations.
Let's illustrate this with an example.
Below, we try to write the first class that specializes XML:
public class XMLFirstSubclass extends XML<OtherXMLSubclass> { ... }
If we're writing the first XML subclass, the only possible values to OtherXMLSubclass is XMLFirstSubclass or not declaring the generic type at all.
First option:
public class XMLFirstSubclass extends XML<XMLFirstSubclass> { ... }
Second:
public class XMLFirstSubclass extends XML { ... }
If you chose to use generics in your class design, the second option seems bad.
Taking a closer look into the first option, it opens the possibility of getting subclasses like:
class XMLSecondSubclass extends XML<XMLFirstSubclass> {
...
}
Note that this compiles perfectly, but will cause class cast exceptions in XMLSecondSubclass method calls at runtime.
I've the following classes
KeyValue.java
package test;
public class KeyValue<T> {
private String key;
private T value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Reader.java
package test;
public interface Reader<T> {
<S extends T> S read(Class<S> clazz);
}
Test.java
package test;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<KeyValue<Object>> list = find(KeyValue.class, new Reader<KeyValue<Object>>() {
#Override
public <S extends KeyValue<Object>> S read(Class<S> clazz) {
return null;
}
});
}
public static <T> List<T> find(Class<T> targetClass, Reader<T> reader) {
return null;
}
}
Here the method call find(......) is failing at compile time with error message
The method find(Class, Reader) in the type Test is not applicable for the arguments (Class, new Reader>(){}).
This method has to return object of type List<KeyValue<Object>>.
What is wrong with this design and how to fix this.
Thank you.
finddefines T and T (in first and second arg) to be of same type - your call to find uses the type Object in the first arg and the Type KeyValue<Object>in the second arg.
Either use two different type identifiers (e.g. T and X, i.e. public static <T, X extends T> List<T> find(Class<T> targetClass, List<X> reader) ) in your find declaration or repair your call to find.
you want to get a list of your class KeyValue from your method find
but u defined it as List note that it is a list of T not KeyValue
change ur method declaration to be as follows
private static <T> List<KeyValue<T> > find(Class<KeyValue> aClass, Reader<KeyValue<T> > reader) {
throw new UnsupportedOperationException("Not yet implemented");
}
i think this is what u want
Try to declare Test as
public class Test<T> {.