i'm new to java and im trying to use the Factory Pattern.
My App simply imports Data from an Excelsheet into an ArrayList by a given Pojo/Bean.
As i have more than one Bean i decided to create a Config object and use a factory pattern.
The cfg object configures the generic extractor and the factory method returns the concrete Extractor. In this case the MyDataExtracor.
The importExcel method simply runs through every line in the excel and adds the extracted data as object per line to a list.
But the line List<MyData> myDataList = e.importExcel();
throws the following error: Type mismatch: cannot convert from List<capture#1-of ?> to List<MyData>
anyone has a hint what im doing wrong?
Heres my code:
main
ExtractorConfig ec = new ExtractorConfig();
ec.setType(MyData.class);
ec.setFileName("MyData.xlsx");
ec.setStartRow(2d);
ec.setEndRow(3241d);
ec.setSheetName("Sheet1");
Extractor e = Extractor.createFromConfig(ec);
List<MyData> myDataList = e.importExcel();
Extractor.java
public abstract class Extractor {
public abstract List<?> importExcel();
public abstract ExtractorBean processRow(Row currentRow);
public static Extractor createFromConfig(ExtractorConfig ec) {
if (ec.getC() == MyData.class)
return new MyDataExtractor(ec);
return null;
}
}
MyDataExtractor.java
public class MyDataExtractor extends Extractor {
ExtractorConfig c;
public MyDataExtractor(ExtractorConfig c) {
super();
this.c = c;
}
#Override
public List<MyData> importExcel() {
List<MyData> aList = new ArrayList<MyData>();
// some code
// loop through worksheet
MyData aMyDataObject = processRow(currentRow);
aList.add(aMyDataObject);
// end of loop
return aList;
}
public MyData processRow(Row currentRow) {
MyData myDataObject = new MyData();
// do some stuff like setting data
return myDataObject;
}
}
In order to use Extractor like you want to itneeds to have a generic type of its own, e.g. Extractor<T> and then public abstract List<T> importExcel(). Then define the concrete implementation as MyDataExtractor implements Extractor<MyData>.
Additionally, you need to adjust the config and factory method, e.g. like this:
public class ExtractorConfig<T> {
public Extractor<T>(Class<T> type) { ... }
Class<T> getType();
}
//need to suppress the warning about the cast
//using E here in order to avoid confusion with <T> of Extractor<T>
#SuppressWarnings("unchecked")
public <E> static Extractor<E> createFromConfig(ExtractorConfig<E> ec) {
//this isn't that elegant though as Extractor would now need to know all implementations and their data classes
if (MyData.class.equals(ec.getType()))
//unfortunately this cast is necessary
return (Extractor<E>)new MyDataExtractor(ec);
return null;
}
And use it like this:
ExtractorConfig<MyData> ec = new ExtractorConfig(MyData.class);
...
Extractor<MyData> e = Extractor.createFromConfig(ec);
List<MyData> myDataList = e.importExcel();
Note that if you want to be more flexible with possible implementations, you might need to use a kind of registry (factory factory) with either contains singleton extractors, prototypes or metafactories.
Simple example using meta factories:
interface ExtractorFactory<T> {
Class<T> getType();
Extractor<T> buildExtractor(ExtractorConfig<T> ec);
}
class ExtractorRegistry {
Map<Class<?>, ExtractorFactory<?>> factories = ...;
void registerFactory(ExtractorFactory<?> factory) {
factories.put(factory.getType(), factory);
}
#SuppressWarnings("unchecked")
<T> Extractor<T> build(ExtractorConfig<T> ec) {
//same ugly but necessary cast, warning needs to be suppressed
ExtractorFactory<T> f = (ExtractorFactory)factories.get(ec.getType());
if( f != null ) return f.buildExtractor(ec);
return null;
}
}
And use it like this:
ExtractorRegistry registry = ...//get it from somewhere (or make it static, but that's not preferred)
registry.registerFactory(new MyDataExtractorFactory());
Extractor<MyData> e = registry .build(ec);
List<MyData> myDataList = e.importExcel();
Finally a word on those casts:
Since you'll want to deal with different and potentially unrelated types in your factory methods (or the registry method that returns factories) you need to cast from the concrete types you get (e.g. MyData defined by MyDataExtractor to the generic or wildcard type of the method.
However, this is ok if you make sure that those casts will always succeed. The warnings are there to tell you this is potentially unsafe and thus you need to be extra careful not to break it. If you are sure this can't break, supress the warnings :)
Related
I have several classes that are doing the same thing : iterates over a List in an object, and add each items in a private field.
I have two objects : MyCustomObject, that have several fields, and ResultOfQuery, where it has a field called data that is a List<Map<String, Object>>.
For example:
private List<MyCustomObject> myCustomObjectList = new LinkedList();
public void setMyCustomObject (ResultOfQuery resultOfQuery){
ObjectMapper objectMapper = new ObjectMapper();
if(resultOfQuery!= null) {
for (Map<String, Object> map : resultOfQuery.getData()) {
myCustomObjectList.add(objectMapper.convertValue(map,
MyCustomObject.class));
}
}
The problem is that I have other classes that does the exact same method, but with another object instead of MyCustomObject.
So I thought that a good idea would be that all of these classes should extends a class that contains this method, and as a parameter it should take first a resultOfQuery, then a list of any objects, and then a Class.
Does it sounds good, or there is a better way to achieve this?
Also, how to give a list of any object ? I tried List<?>, but this shows me the following error :
Error at list add line
You can achieve type safety with generics and inheritance. If you declare a base class having the common stuff like:
public class BaseClass<T> {
private List<T> tList = new LinkedList<>();
private final Class<T> classT;
public BaseClass(Class<T> classT) {
this.classT = classT;
}
public void setObject (ResultOfQuery resultOfQuery){
ObjectMapper objectMapper = new ObjectMapper();
if(resultOfQuery!= null) {
for (Map<String, Object> map : resultOfQuery.getData()) {
tList.add(objectMapper.convertValue(map, classT));
}
}
}
}
Then it is easy to extend it for each different type, like:
public class MyCustomObjectExtendedClass extends BaseClass<MyCustomObject> {
public MyCustomObjectExtendedClass() {
super(MyCustomObject.class);
}
}
I have renamed stuff because it was decoupled from the MyCustomObject.
You can use private List myCustomObjectList = new LinkedList();
Instantiating a class using a raw type (i.e. without a type parameter, as in List list = new ArrayList(3)), is something you shouldn't do, as it is less type-safe, and is only allowed for backwards compatibility.
Link: Java Generics List and ArrayList with and without Parameters
We had a use case where a specific request object say A must be converted to a class of type B or type C. For that we wrote static methods mapToB(A) and mapToC(A). But wouldn't it be better to have a polymorphic map method of type map(A, B) and map(A, C). I know that output arguments are considered an anti-pattern, but the 2nd implementation looks cleaner.
In my opinion I would prefer a converter which takes a object of type A and the target type and build the object of the target type for you. I think this is much cleaner than a static method and gives you the possibility to extends the mapping in future if needed. E.g.:
class Converter{
private final objectToConvert;
public Converter(A objectToConvert){
this.objectToConvert = objectToConvert;
}
public <T> T convert(Class<T> targetType){
T res;
// ... Do the convertion
return res;
}
}
Now you are able to do the convertion in a clean and readable way.
A a = new A();
B b = new Converter(a).convert(B.class);
C c = new Converter(a).convert(C.class);
But wouldn't it be better to have a polymorphic map method of type
map(A, B) and map(A, C)
You could have something of near :
<T> T map(Object source, Class<T> target)
Where source is any Object and target the class of the instance to return.
For example :
public class Mapper {
public static <T> T map(Object source, Class<T> target) {
T converted = null;
// ...
return converted;
}
}
And you can call it :
MyClass myClass = new MyClass(...);
MyOtherClass myOtherClass = Mapper.map(myClass, MyOtherClass.class);
I have a generic class in java defined as:
public static class KeyCountMap<T>
{
private Map<T, MutableInt> map = new LinkedHashMap<T, MutableInt>();
// ... rest of the properties...
public KeyCountMap()
{ }
#SuppressWarnings({ "unchecked", "rawtypes" })
public KeyCountMap(Class<? extends Map> mapType) throws InstantiationException, IllegalAccessException
{
map = mapType.newInstance();
}
//... rest of the methods...
}
I have defined same class in .NET as:
public static class KeyCountMap<T>
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
{
obj = new T(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
}
And then a method is defined to sort map of type KeyCountMap<T> by value in the descending order . The method is defined as:
public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> _map)
{
List<KeyValuePair<T, MutableInt>> _list = new List<KeyValuePair<T, MutableInt>>(_map.EntrySet());
// whereas _map.EntrySet() return of type HashSet<KeyValuePair<T, MutableInt>>
_list = _list.OrderByDescending(_x => _x.Value).ToList();
KeyCountMap<T> _result = new KeyCountMap<T>();
foreach (KeyValuePair<T, MutableInt> _entry in _list)
{
_result.Put(_entry.Key, _entry.Value);
}
return _result;
}
How can I get corrected the class defined in .NET ?
I assume you know Java erases any generic type information after compiling (there's metadata for variables, but actual objects are void of generic type information). Moreover, your code is not type safe:
#SuppressWarnings({ "unchecked", "rawtypes" })
You're using this because you're creating a non-parameterized instance of Map.
In .NET, you don't get around the type system like this, because generic type information is kept and used at runtime.
Let's see your C# code:
public static class KeyCountMap<T>
A static class in C# is a class that cannot be instanced, it's used for its static members alone. I think you don't want this. Perhaps KeyCountMap is a static nested class in Java, as opposed to an inner class.
In C#, you don't have inner classes. Nested classes don't share data with an instance of the containing class, it's as if the name of the containing class is part of the namespace for the nested class. So, you don't need, and actually don't want, the static keyword here.
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
In .NET, Dictionary is a class. To keep the intent, you should use IDictionary, the corresponding interface, as the type for the map field.
// ... rest of properties...
public KeyCountMap()
{ }
public void KeyCountMap<T>(T obj) where T : Dictionary<T, MutableInt>
Why the void return type, isn't this a constructor?
In C#, constructors can't be generic. You probably want a Type.
Your C# code just doesn't make sense, so here's what you could do:
public KeyCountMap(Type dictionaryType)
{
if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
{
throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", nameof(dictionaryType));
}
map = (IDictionary<T, MutableInt>)Activator.CreateInstance(dictionaryType);
}
}
We're checking the type before creating an instance. If we didn't, we would create an instance, the cast would fail and the assignment wouldn't even happen, so the new instance would just be garbage.
It may be that the actual instance will be a proxy; if so, you may not want to check the type before creating an instance.
You can't just copy-paste Java as C# (or vice-versa) and expect to make just a few changes until it works, for some definition of works, e.g. it compiles. The languages are not that similar, and chances are that too many subtle things are wrong.
This approach might be fun at first, but you'll stumble so often it will soon stop being any fun at all. You should learn the basics and understand the way things are done in the target language before you start translating code line-by-line. Many times, you may find that something you had to do in one environment already exists in the other or vice-versa, or that something may take more or less steps to do in the other, etc.
In this particular case, Java made Class be a generic class, while .NET kept Type a non-generic class. In .NET only interfaces and delegates may state generic type covariance or contravariance. This is rather restrictive anyway, if Type was generic, the intended uses could be either covariant or contravariant. But remember that in Java, a generic Class<T> at runtime is as good as Class, it only has any value at compile time and you can tell the compiler you know better anyway, just like you did.
There are two problems. First, you need to tell the compiler that T has a parameterless constructor, so you can call new T(). You can do that by providing the new() argument to the class definition.
You also have to tell the compiler that T is actually the dictionary you are trying to assign, so we have to extend the class a little more:
public class KeyCountMap<K>
{
private Dictionary<K, MutableInt> map = new Dictionary<K, MutableInt>();
// ... rest of properties...
Note that K is the key type of the dictionary, which you didn't specify yet.
Second, the T in your method can be another T than in your class. Omitting that will do the trick:
public void Map()
{
var obj = new Dictionary<K, MutableInt>(); // Unable to define new instance of T
map = obj; // Unable to convert T to base class
}
Maybe this is what you want?
public class KeyCountMap<T>
where T : new()
{
private Dictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
// ... rest of properties...
public KeyCountMap()
{ }
public KeyCountMap(T obj)
{
obj = new T();
map = (Dictionary<T, MutableInt>)(object)obj;
}
}
I am hoping to reach the Java generics experts here. Let's say you have some typed class:
public interface SomeClass<T> {
void doSomething(final T t);
}
There is also a function which gets you an instance of T given an instance of SomeClass<T>:
public static class Retriever {
public <T> T get(final SomeClass<T> c) {
return null; // actual implementation left out
}
}
Now let's say you have a collection of SomeClass<?> and a retriever:
final List<SomeClass<?>> myClasses = null; // actual implementation left out
final Retriever myRetriever = null; // actual implementation left out
We are not able to do the following:
for (final SomeClass<?> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
Now my question: does Java need support to be able to locally define a type? Something like:
<T> for (final SomeClass<T> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
Here, the type T is scoped to the for-loop. We are defining T to get rid of the wildcard ?. That's it. The introduction of T should enable us to write the desired for loop as expressed above.
FWIW, the following code is a workaround. We are introducing a function, solely for the conversion of ? to T.
for (final SomeClass<?> myClass : myClasses) {
workAround(myRetriever, myClass);
}
public static <T> void workAround(final Retriever myRetriever, final SomeClass<T> myClass) {
myClass.doSomething(myRetriever.get(myClass));
}
A locally defined user type might be a more elegant solution?
Now my question: does Java need support to be able to locally define a type?
No. The minimal scope of a type-parameter is the method, i.e. in order to have the type T available for your for loop, you will have to either defined the enclosing method a generic or the enclosing class. For example:
<T> void method(List<SomeClass<T> myClasses) {
for (final SomeClass<T> myClass : myClasses) {
myClass.doSomething(myRetriever.get(myClass));
}
}
I'm trying to build an SDK using an adapter pattern. Here's what I've got so far:
interface Adapter<T> {
void doWork(WorkUnit<T> unit);
Class<T> getT();
}
class WorkUnit<T> {
public int getId() { ... }
public T getExtras() { ... }
}
class OldWorkUnit {
public <T> void setExtra(T data) { /* Store data in Map<Class, Object> */ }
public <T> WorkUnit<T> toNewWorkUnit(Adapter<T> adapter) { /* Map.get(adapter.getT()) */ }
}
There's a good amount of generics in there, but I can't know T at compile time, and there may be multiple Adapters, all with different types of T. This is meant to be exposed to third parties, so I also need as little implementation as possible in the interface implementation, and it has to be an interface (no abstract class).
Now I want to take this and call doWork with a WorkUnit. My first pass at the code looks like this:
class FooAdapter implements Adapter<FooWorkUnit> {
...
}
OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());
Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);
a.doWork(unit);
Uh oh, that doesn't compile:
The method doWork(WorkUnit<capture#2-of ?>) in the type Adapter<capture#2-of ?>
is not applicable for the arguments (WorkUnit<capture#4-of ?>)
I know that the WorkUnit generic argument is the same type as the Adapter.doWork() generic argument, but without knowing the type I can't cast it appropriately.
So is there a way to work my way through this?
Why do you wildcard the template class here?:
Adapter<?> a = new FooAdapter();
WorkUnit<?> unit = w.toNewWorkUnit(a);
If you do this:
Adapter<FooWorkUnit> a = new FooAdapter();
WorkUnit<FooWorkUnit> unit = w.toNewWorkUnit(a);
Doesn't that preserve what you need?
Now the compiler knows that FooWorkUnit is the common denominator, so to speak.
Edit: OK point taken about the runtime variability. How about strongly-typing the method that does the work, so that the wildcards are eliminated, but still consistent:
#SuppressWarnings("unchecked")
public <X> void prepareArgsAndDoTheWork() {
OldWorkUnit w = new OldWorkUnit();
w.setExtra(new FooWorkUnit());
Adapter<X> a = (Adapter<X>) ... ; // Obtain the Adapter by reflection etc
WorkUnit<X> unit = w.toNewWorkUnit(a);
a.doWork(unit);
}