Getting key from object for Map using object and interface - java

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;
}
});

Related

Why can't I use a class that implements List<X> where a List<X> is expected?

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.

How to initializing Class<T> at interface default method?

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.

Using generics for a class how can I convert the values from one type to another?

I built a simple document store, there are entities that have fields of different types, I have a Float, Int and String type. The entity contains an array list of values, if someone updates the schema of the entity I would like to be able to try to convert the values to the new type.
public interface FieldType<T> {
ArrayList<T> values;
}
public class FloatField implements FieldType<Float> {
}
public class StringField implements FieldType<String> {
}
I have thought about using a abstract class with methods as below
public abstract class Field<T> implements FieldType<T> {
abstract public <T> castFromString(String value);
abstract public <T> castFromFloat(Float value);
abstract public <T> castFromInt(Int value);
}
public class FloatField extends Field<Float> {
#override
public <Float> castFromString(String value){
Float castValue = null;
try {
castValue = Float.parseFloat(value);
} catch(Exception e){
}
return castValue;
}
}
I did not really like this solution as I would have to add a new abstract method each time I added an extra type to the system.
Any ideas how I could implement this better?
Maybe you could use the Function<T, R> interface?
public abstract class Field<T> implements FieldType<T> {
...
public <F> T convert(F value, Function<F, T> converter) {
try {
return converter.apply(value);
} catch(Exception e) {
return null;
}
}
...
}
And then specify the converter using a lambda expression or a method reference:
field.convert("1234", BigDecimal::new); //with a method reference
field.convert("1234", s -> new BigDecimal(s)) //with a lambda
This would replace all of your convertXXX methods by one since the return type is inferred from the passed Function.
EDIT:
If you want automatic converting, you would of course have to hard-code these since you wouldn't want to write conversion methods for all 4240 classes in the Java API. This gets messy, though. Maybe something like this in a static helper class or in FieldType itself?
public class WhereverYouWantThis {
private static HashMap<Class<?>, HashMap<Class<?>, Function<?, ?>>> converters = new HashMap<>();
static {
putConverter(String.class, Float.class, Float::parseFloat);
}
private static <T, R> void putConverter(Class<T> t, Class<R> r, Function<T, R> func) {
HashMap<Class<?>, Function<?, ?>> map = converters.get(t);
if(map == null) converters.put(t, map = new HashMap<>());
map.put(r, func);
}
public static <T, R> Function<T, R> getConverter(Class<T> t, Class<R> r) {
HashMap<Class<?>, Function<?, ?>> map = converters.get(t);
if(map == null) return null;
#SuppressWarnings("unchecked")
Function<T, R> func = (Function<T, R>) map.get(r);
return func;
}
public static <T, R> R convert(T o, Class<R> to) {
#SuppressWarnings("unchecked")
Function<T, R> func = (Function<T, R>) getConverter(o.getClass(), to);
return func == null ? null : func.apply(o);
}
}
I don't think you need generics for this. Instead, just try to create a Float from the input String and return null if there be a problem:
public Float castFromString(String value) {
Float castValue = null;
try {
castValue = Float.parseFloat(value);
} catch(Exception e){
// log here
}
return castValue;
}
The reason I don't think generics are needed is that the types involved in the conversion are named/known in your helper methods.

Java - generics & wildcards & interface versus implementation

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

Can generics allow the Java compiler to check the type of keys and values in a map?

I am in a situation where I want to have a map where the keys are an interface class, and the corresponding value is a class which implements that interface. In other words the key and value type is related.
My current implementation of the method which adds to the map, and gets an instance of the implementation class looks like:
// should be something like Class<T>, Class<? extends T>
static Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>> ();
public static <T> void add(Class<T> interfaceT,
Class<? extends T> implementationT) {
map.put(interfaceT, implementationT);
}
public static <T> T get(Class<T> interfaceT) {
// cast caused by definition not complete.
Class<T> implementationT = (Class<T>) map.get(interfaceT);
// try catch stuff omitted
T t = implementationT.newInstance();
return t;
}
My question is:
Can I define the "map" variable so the cast in the get(...) method is unneeded? I could not make the " new HashMap<Class<T>, Class<? extends T>>()' work, so either it is impossible or I missed something fundamental :)
Please advise :)
Edit: It turned out that the asSubclass() method on Class did what I wanted :D
Class<?> rawClassFromMap = map.get(interfaceT);
Class<? extends T> implementationT = rawClassFromMap.asSubclass(interfaceT);
It is fine that implementationT is of type "? extends T" as I just need a T object returned.
I like generics. Reminds me of Haskell...
It looks like the goal is something like the "Typesafe Heterogenous Container" described by Josh Bloch in Chapter 5 of Effective Java (item 29). In his case, he's mapping a type (Class<T>) to an (already-instantiated) instance (T).
You can do something similar, using asSubclass instead of cast:
final class Factory
{
private Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
<T> void map(Class<T> type, Class<? extends T> impl)
{
map.put(type, impl.asSubclass(type));
}
private <T> Class<? extends T> get(Class<T> type)
{
Class<?> impl = map.get(type);
if (impl == null)
throw new IllegalArgumentException("Unknown type: " + type);
return impl.asSubclass(type);
}
<T> T create(Class<T> type)
throws Exception
{
Class<? extends T> impl = get(type);
Constructor<? extends T> ctor = impl.getConstructor();
return ctor.newInstance();
}
}
I would suggest a Proxy. Here's the Java example.
public interface Bike {
public String getWheels();
public int getSize();
}
public class MountainBike implements Bike {
#Override
public int getSize() {
return 24;
}
#Override
public String getWheels() {
return "Treaded";
}
#Override
public String toString() {
String newLine = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append("Type: MOUNTAIN").append(newLine);
sb.append("Wheels: ").append(getWheels()).append(newLine);
sb.append("Size: ").append(getSize()).append(newLine);
return sb.toString();
}
}
public class CruiserBike implements Bike {
#Override
public int getSize() {
return 26;
}
#Override
public String getWheels() {
return "Smooth";
}
#Override
public String toString() {
String newLine = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append("Type: CRUISER").append(newLine);
sb.append("Wheels: ").append(getWheels()).append(newLine);
sb.append("Size: ").append(getSize()).append(newLine);
return sb.toString();
}
}
public class BikeProxy implements InvocationHandler {
private Object obj;
public static Object newInstance(Object obj)
{
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new BikeProxy(obj));
}
public static <T> T newInstance(String className)
{
try
{
return (T) newInstance(Class.forName(className));
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
public static <T> T newInstance(Class<T> bikeClass)
{
try
{
return (T) java.lang.reflect.Proxy.newProxyInstance(Bike.class.getClassLoader(), new Class[]{Bike.class},
new BikeProxy(bikeClass.newInstance()));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private BikeProxy(Object obj)
{
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable
{
Object result;
try
{
result = m.invoke(obj, args);
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return result;
}
}
public class ProxyTester
{
public static void main(String[] args)
{
Bike mountainBike = BikeProxy.newInstance(MountainBike.class);
System.out.println(mountainBike);
Bike mountainBike2 = BikeProxy.newInstance(MountainBike.class.getName());
System.out.println(mountainBike2);
Bike cruiserBike = BikeProxy.newInstance(CruiserBike.class);
System.out.println(cruiserBike);
Bike cruiserBike2 = BikeProxy.newInstance(CruiserBike.class.getName());
System.out.println(cruiserBike2);
}
}

Categories