Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a class in a type-safe way

Tags:

java

generics

I'd like to write a type-safe code. Here's what I've tried:

public interface ResultTronsformer<T>{
    public T tranform(T t);
}

public class BigDecimalTransformer implements ResultTRansformer<BigDecimal>{

    public BigDecimal transform(BigDecimal t){
        return t.setScale(0);
    }
}

Now I define the Column interface which looks like

public interface Column{
    public ResultTransformer<?> getTransformer();
}

and would like to use it in the method

public class Report{
    private Map<Column, Object> columnValuePairs;

    public void putIntoACollection(Column c, Object columnsValue){
         ResultTransformer<?> rt = c.getTransformer();
         columnValuePairs.put(c, rt.transform(o)); //Error: Couldn't convert Object 
                                                   //to the capture of wildcard
    }
}

How can I rearrange the design to reach the desirable type-safety? Maybe I should do the type-checking at runtime instead (throwing an exception)?

like image 345
user3663882 Avatar asked Sep 27 '22 15:09

user3663882


2 Answers

You can think about the Column just like it is some kind of container that holds specific type. In that way, you can introduce generic type in Column declaration.

public interface Column<T>{
    public ResultTransformer<T> getTransformer();
}

Then, you can change Report method as follows:

public <T> void putIntoACollection(Column<T> c, T columnsValue){
        ResultTransformer<T> rt = c.getTransformer();
        columnValuePairs.put(c, rt.transform(columnsValue)); 
}
like image 181
ppro Avatar answered Oct 12 '22 23:10

ppro


When you get the transformer, you need to specify the type because the compiler won't know it at that time.

A possible solution is to add the class as a parameter to the getTransformer of the Column and return a specialized ResultTransformer.

public interface ResultTransformer<T> {
    public T transform(T t);
}

public interface Column{
    public <T> ResultTransformer<T> getTransformer(Class<T> theClass);
}

public class Report{
   private Map<Column, Object> columnValuePairs;

   public void putIntoACollection(Column c, Object o){
       ResultTransformer<Object> rt = c.getTransformer(Object.class);
       columnValuePairs.put(c, rt.transform(o));
   }

public interface ResultTransformer<T> {
    public T transform(T t);
}

Another way would be to generalize the interface Column.

like image 30
Maarten Avatar answered Oct 13 '22 01:10

Maarten