I am trying to create a Holder class for different objects to be used in my application, I ended up with this code that works fine until some extent, the builder pattern works fine for the optional fields, but I guess this holder could be refactored to accept any arbitrarily number of parameter
package pojos;
public class Holder<T, R, S, U> {
private final T t;
private final R r;
private final S s;
private final U u;
private Holder(final Builder<T, R, S, U> builder) {
this.t = builder.t;
this.r = builder.r;
this.s = builder.s;
this.u = builder.u;
}
public T getField1() {
return this.t;
}
public R getField2() {
return this.r;
}
public S getField3() {
return this.s;
}
public U getField4() {
return this.u;
}
public static class Builder<T, R, S, U> {
private T t;
private R r;
private S s;
private U u;
public Builder field1(final T t) {
this.t = t;
return this;
}
public Builder field2(final R r) {
this.r = r;
return this;
}
public Builder field3(final S s) {
this.s = s;
return this;
}
public Builder field4(final U u) {
this.u = u;
return this;
}
public Holder<T, R, S, U> build() {
return new Holder<>(this);
}
public Builder<T, R, S, U> copy(final Holder<T, R, S, U> rowMappingsHolder) {
this.t = rowMappingsHolder.getField1();
this.r = rowMappingsHolder.getField2();
this.s = rowMappingsHolder.getField3();
this.u = rowMappingsHolder.getField4();
return this;
}
}
}
Example of usage:
protected Holder<Row, Map<Integer, String>, Void, Void> getRowMapHolder(Row row, Map<Integer,String> map) {
return (Holder<Row, Map<Integer, String>, Void, Void>) new Holder.Builder<Row, Map<Integer, String>,Void, Void>().field1(row).field2(map).build();
}
Any ideas?
Regards
~Marco
How this should work for different number of parameters? You have finite number of accessors, so you cannot use, for example, h.getField2147(), if you don't declare it.
Another way to have a tuple for different number of objects is heterogeneous array. In Java, ofc, you may just use Object[] and you can wrap it with class, which have methods
public <T> T getField(int i) {
return (T) arr[i];
}
and then use like h.<String>getField(2147)
But creating different classes for tuples of different size (like your for 4 objects) is better.
Thanks to Andy's comment and Google Autovalue, a good solution arose:
So we can create different classes that have meaning, no more "field1", "field2"...
package pojos;
import com.google.auto.value.AutoValue;
import org.apache.poi.ss.usermodel.Row;
import java.util.Map;
#AutoValue
public abstract class RowMapHolder {
public abstract Row row();
public abstract Map<Integer,String> mapping();
public static RowMapHolder create(Row row, Map<Integer, String> mapping) {
return new AutoValue_RowMapHolder(row, mapping);
}
}
or
package pojos;
import com.google.auto.value.AutoValue;
import java.util.List;
import java.util.Map;
#AutoValue
public abstract class KeyValuesMapHolder {
public abstract List<KeyValue<String,String>> keyValues();
public abstract Map<Integer,String> mapping();
public static KeyValuesMapHolder create(List<KeyValue<String, String>> keyValues, Map<Integer, String> mapping) {
return new AutoValue_KeyValuesMapHolder(keyValues, mapping);
}
}
Related
First the simple case (A):
public class PsList implements List<Ps> { ... }
elsewhere
private void doSomething(List<Ps> list) { ... }
// compiles
List<Ps> arrayList = new ArrayList<Ps>();
doSomething(arrayList);
// does not compile
PsList psList = new PsList();
doSomething(psList);
Ok. I know that I can change this to "work" by adding ? extends as such:
private void doSomething(? extends List<Ps> list) { ... }
// compiles
List<Ps> arrayList = new ArrayList<Ps>();
doSomething(arrayList);
// compiles
PsList psList = new PsList();
doSomething(psList);
My question is why do I need to do that? It makes no sense to me. I am implementing the exact interface that is is expecting. I can pass other List types other than ArrayList why not mine?
Life is always more complicated than this, so my real coding issue is (B):
public class PsList implements List<Ps> { ... }
private void doSomething(Map<String, ? extends List<Ps>> map, Boolean custom) {
...
// need to create a new List<Ps> of either an ArrayList<Ps> or PsList
map.put("stringValue", custom ? new PsList() : new ArrayList<Ps>());
...
}
So, in either case Java is complaining that map is expecting ? extends List as the value.
even if I change this to be:
List<Ps> list = new ArrayList<>();
List<Ps> psList = new PsList();
map.put("string", custom ? psList : list);
and of course this doesn't compile:
? extends List<Ps> list = new ArrayList<>();
? extends List<Ps> psList = new PsList();
map.put("string", custom ? psList : list);
So what am I supposed to do to get something like this to work?
Edit 1:
Ok, a minimal reproduction:
Ps.java
package com.foo;
public class Ps
{
}
PsList.java
package com.foo;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class PsList implements List<Ps>
{
#Override
public int size()
{
return 0;
}
#Override
public boolean isEmpty()
{
return false;
}
#Override
public boolean contains(Object o)
{
return false;
}
#Override
public Iterator<Ps> iterator()
{
return null;
}
#Override
public Object[] toArray()
{
return new Object[0];
}
#Override
public <T> T[] toArray(T[] a)
{
return null;
}
#Override
public boolean add(Ps ps)
{
return false;
}
#Override
public boolean remove(Object o)
{
return false;
}
#Override
public boolean containsAll(Collection<?> c)
{
return false;
}
#Override
public boolean addAll(Collection<? extends Ps> c)
{
return false;
}
#Override
public boolean addAll(int index, Collection<? extends Ps> c)
{
return false;
}
#Override
public boolean removeAll(Collection<?> c)
{
return false;
}
#Override
public boolean retainAll(Collection<?> c)
{
return false;
}
#Override
public void clear()
{
}
#Override
public Ps get(int index)
{
return null;
}
#Override
public Ps set(int index, Ps element)
{
return null;
}
#Override
public void add(int index, Ps element)
{
}
#Override
public Ps remove(int index)
{
return null;
}
#Override
public int indexOf(Object o)
{
return 0;
}
#Override
public int lastIndexOf(Object o)
{
return 0;
}
#Override
public ListIterator<Ps> listIterator()
{
return null;
}
#Override
public ListIterator<Ps> listIterator(int index)
{
return null;
}
#Override
public List<Ps> subList(int fromIndex, int toIndex)
{
return null;
}
}
OtherService.java
package com.foo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OtherService
{
private void doSomething(Map<String, List<Ps>> map, Boolean custom)
{
if (custom)
{
map.put("someValue", new PsList());
} else {
map.put("someValue", new ArrayList<>());
}
}
private void callDoSomethingNotCustom()
{
Map<String, List<Ps>> map = new HashMap<>();
doSomething(map, false);
}
private void callDoSomethingCustom()
{
Map<String, PsList> map = new HashMap<String, PsList>();
// map is not the right format
doSomething(map, true);
}
}
Wrong 1st argument type. Found: 'java.lang.String,com.foo.PsList>', required: 'java.util.Map>'
As you seemed to realize halfway through your question, your problem is not about List<Ps> being interchangeable with PsList.
The problem is that you can’t add to a Map<String, ? extends List<Ps>>.
Let’s consider a simpler example:
void doSomething(Map<String, ? extends Number> map) {
map.put(String, Integer.valueOf(0)); // Not allowed.
}
The problem is that Map<String, ? extends Number> does not mean “values can be Number or any subclass of Number.”
Every generically typed object has a specific, non-wildcard type. Meaning, there does not exist a Map whose type is Map<String, ? extends Number>. However, the following can exist:
Map<String, Integer> (allows Integer values only)
Map<String, Double> (allows Double values only)
Map<String, Number> (allows values of any Number subclass)
Map<String, ? extends Number> refers to a Map that might be any one of the above (or, of course, any other specific Number subclass). The compiler doesn’t know which specific type the Map’s values are, but the Map still has a specific type for its values which does not make use of ? in any way.
So, looking at the example method again:
void doSomething(Map<String, ? extends Number> map) {
// Not allowed. The caller might have passed a Map<String, Double>.
map.put(String, Integer.valueOf(0));
// Not allowed. The caller might have passed a Map<String, Integer>.
map.put(String, Double.valueOf(0));
// Not allowed. The caller might have passed a Map<String, Integer>
// or Map<String, Double>. This method has no way of knowing what the
// actual restriction is.
Number someNumber = generateNewNumber();
map.put(String, someNumber);
}
Indeed, you cannot add anything to a Map or Collection whose type is an upper bound wildcard, because there is no way to know whether it’s correct and safe to do so.
In your case, the simplest solution is to remove the wildcard:
private void doSomething(Map<String, List<Ps>> map, boolean custom) {
// ...
map.put("stringValue", custom ? new PsList() : new ArrayList<Ps>());
}
If you really have Maps with different value types, you would need to tell the method the specific type being used:
private <L extends List<Ps>> void doSomething(Map<String, L> map,
Supplier<L> listCreator) {
// ...
map.put("stringValue", listCreator.get());
}
And then you can call the method like this:
if (custom) {
doSomething(psMap, PsList::new);
} else {
doSomething(listMap, ArrayList::new);
}
You can absolutely do that. Here is an example:
public class MyClass {
static interface FooList<T> {}
static class Ps {}
static void doSomething(FooList<Ps> list) { }
static class PsList implements FooList<Ps> { }
public static void main(String[] args)
{
FooList psList = new PsList();
doSomething(psList);
System.out.println("HelloWorld!");
}
}
See demo here.
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 have a Table class that implements a ForwardingMultimap of a certain type of object. I was wondering if it was over-doing it to create an interface that extracted the key from the object so it wouldn't be annoying for the caller to handle "Entry" objects when they call "values". Or would it just be better to have the caller put the object and key in themselves? If this is okay, would creating a separate class to handle each key like below be better, or should the caller implement it themselves ?
public class CustomObject {
public String propertyOne;
public int propertyTwo;
}
public interface ITableAggKey {
Object getKey(CustomObject customObj);
}
public class Table extends ForwardingMultimap<Object, CustomObject> {
Multimap m_map;
public Table(ITableAggKey aggKey){
m_map = HashMultimap.create();
m_aggKey = aggKey;
}
public boolean put(CustomObject obj) {
m_map.put(m_aggKey.getKey(obj), obj);
}
}
public class CustomObjectAggKeys {
public static final aggKeyOne = new ITableAggKey(){
#Overide
public Object getKey(CustomObject obj){
return obj.propertyOne;
}
};
public static final aggKeyOne = new ITableAggKey(){
#Overide
public Object getKey(CustomObject obj){
return obj.propertyTwo;
}
};
}
public class Table<K, T> extends ForwardingMultimap<K, T> {
Multimap<K, T> m_map;
Function<T, K> m_aggKey;
public Table(Function<T, K> aggKey){
m_map = HashMultimap.create();
m_aggKey = aggKey;
}
public boolean put(T obj) {
m_map.put(m_aggKey.apply(obj), obj);
}
}
public static void main(String[] args) {
Table<String, CustomObject> IndexOne = new Table<>(x -> x.propertyOne);
Table<Integer, CustomObject> IndexTwo = new Table<>(x -> x.propertyTwo);
}
If you cannot use Java8. Add Function interface.
public interface Function<T, K> {
K apply(T arg);
}
And
Table<String, CustomObject> indexOne = new Table<>(new Function<CustomObject, String>() {
#Override public String apply(CustomObject obj) {
return obj.propertyOne;
}
});
I have a question about Java generics. Say I have the following interface:
public static class Something<T> {
public void set(T t) {
}
}
public static interface Manager<T> {
public void add(final String key, final Something<T> o);
public Something<T> get(final String key);
}
An example of usage:
final Manager<Number> m = ...;
m.add("key", new Something<Number>());
m.get("key").set(new Integer(5));
I would also like to be able to add Something<Integer>, Something<Double>, ... to the a Manager<Number>. I would say I have to change the signature of the add-function:
public static interface Manager<T> {
public void add(final String key, final Something<? extends T> o);
public Something<T> get(final String key);
}
final Manager<Number> m = ...;
m.add("key", new Something<Integer>());
m.get("key").set(new Integer(5));
So far, so good. Let's look at a possible implementation of the manager:
public static class ManagerImplementation<T> implements Manager<T> {
protected HashMap<String, Something<T>> map = new HashMap<String, Something<T>>();
public void add(final String key, final Something<? extends T> o) {
map.put(key, o); // <--- here
}
public Something<T> get(final String key) {
return map.get(key);
}
}
This fails, since you cannot add a Something<? extends T> to a Map<X, Something<T>>. So let's change this:
public static class ManagerImplementation<T> implements Manager<T> {
protected HashMap<String, Something<? extends T>> map = new HashMap<String, Something<? extends T>>();
public void add(final String key, final Something<? extends T> o) {
map.put(key, o);
}
public Something<T> get(final String key) {
return map.get(key); // <--- here
}
}
This fails since map.get(key) returns Something<? extends T> while the get-function is required to return Something<T>, as defined in the interface.
What is the common approach to solve this?
Thanks!
Inside your class you are always using Something<? extends T>, thus in your public get method you must convert the inside world to the outside world format. E.g. you can simply cast the result of map.get(key) to Something<T>:
return (Something<T>) map.get(key); // <--- here
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.