Type Parameter Class with generic java - java

I am trying to use the generic class in java 15 with the below code
#Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
public GenericRepository(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, T.class);
}
}
I can't use T.class, how can I solve this
Solution I found
#Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
private final Class<T> typeParameterClass;
public GenericRepository(MongoClient mongoClient, Class<T> typeParameterClass) {
this.mongoClient = mongoClient;
this.typeParameterClass = typeParameterClass;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, this.typeParameterClass);
}
}
Since using this solution is quite extra code, is there any better way to do this ?

A singleton class, whose only constructor takes parameters, and is parameterized?
Your code makes no sense. The problem you're running into is significant in other contexts, but not this one. There is no direct solution to this problem (the problem being: Generics are erased), but there are different code styles that avoid it.
The problem is, because the problem doesn't even apply to this situation, it's hard to explain how one would rewrite this code so the problem goes away as a general principle.
Here, you'd just... remove the type param, get rid of that interface (in general if you have IFoo hanging around, something's not right), simple as that.
If you want to generalize this concept, so that you can make a lot of these (Let's say you have one of these classes to retrieve the Foos, and another to retrieve the Bars), you CAN fetch the <X> in specifically public class FooFetcher implements GenericFetcher<X>, though it's a bit tricky (you'd use getGenericSuper from your own java.lang.Class and take it from there. There's a ton of caveats in this situation, so I won't expand any further on this, just know that's how you could do it.
If, in a different situation, you do need to convey generics in a runtime-queryable way, the problem with your style is that a class object and a generics param overlap but aren't the same. int has a class object (int.class), but List<int> is not valid java code. List<String> is valid generics (List<List<String>> x; is valid java), but List<String>.class isn't a thing and never will be, only List.class can be. Same goes for ?, ? extends Map<?, List<? extends Number>> & Serializable, which is valid generics, but rather obviously not at all something you can represent with a java.lang.Class type. Therefore, if you do want generics as a runtime queryable concept, search the web for 'super type tokens' - but note that they require MORE code than what you have here, not less. They're just actually capable of representing exactly what generics can represent.
As a general rule of thumb if you're relying on the generics of java.lang.Class to glue your code together you've done something wrong, and you probably want factories.

Related

Proper use of generics in abstract java class?

EDIT: This question is not well worded, and the provided answer is correct in a literal sense but did not teach me how to attain what I needed. If you are struggling with the same problem, this is what finally helped me: How to enforce child class behavior/methods when the return types of these methods depends on the child class?
I am trying to implement a basic matrix class from a boilerplate abstract class I wrote. There will be several implementations of this abstract class, each one using a different math library, which I will then test for speed.
Each implementation will hold its data in that library's native matrix data structure. I think this is a use case for generics. At this point I think I've read too many tutorials and watched too many videos, as I just can't seem to figure out all the right places to put the T Notation to make this work correctly.
So my question is twofold:
Have I misused or missed the point of generics?
If not, what is the correct syntax for their use?
I've read the docs plus about three different tutorials and still can't understand.
Here is what I've tried:
public abstract class BaseMatrix<T> {
protected int[] shape;
protected int nrows;
protected int ncols;
protected T data; // <--- Here is the generic data --->
public BaseMatrix(int rows, int cols){
this.nrows = rows;
this.ncols = cols;
this.shape = new int[]{nrows, ncols};
}
public abstract BaseMatrix mmul(BaseMatrix other);
And here is my implementation:
public class ND4JDenseMatrix extends BaseMatrix{
// private INDArray data;
public ND4JDenseMatrix(int rows, int cols) {
super(rows, cols);
this.data = Nd4j.zeros(this.shape); <--- Here is the non-generic data --->
}
#Override
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
ND4JDenseMatrix result = new ND4JDenseMatrix(nrows, ncols);
result.data = data.mmul(other.data);
return result;
}
The error is: Method does not override method from its superclass.
hold its data in that library's native matrix data structure. I think this is a use case for generics.
Generics serves to link things. You declared the type variable with <T>, and you've used it in, as far as your paste goes, exactly one place (a field, of type T). That's a red flag; generally, given that it links things, if you use it in only one place that's usually a bad sign.
Here's what I mean: Imagine you want to write a method that says: This method takes 2 parameters and returns something. This code doesn't particularly care what you toss in here, but, the parameters must be the same type and I return something of that type too. You want to link the type of the parameter, the type of the other parameter, and the return type together.
That is what generics is for.
It may apply here, if we twist our minds a bit: You want to link the type of the data field to a notion that some specific implementation of BaseMatrix can only operate on some specific type, e.g. ND4JMatrix.
However, mostly, no, this doesn't strike me as proper use of generics. You can avoid it altogether quite easily: Just.. stop having that private T data; field. What good is it doing you here? You have no idea what type that is, you don't even know if it is serializable. You know nothing about it, and the compiler confirms this: There is absolutely not one iota you can do with that object, except things you can do to all objects which are generally quite uninteresting. You can call .toString() on it, synchronize on it, maybe invoke .hashCode(), that's about it.
Why not just ditch that field? The implementation can make the field, no need for it to be in base!
public class ND4JDense extends BaseMatrix {
private ND4JMatrix data; // why not like this?
}
(This code assumes 'ND4JMatrix' is the proper data type you desire here, a thing that can is the internal representation for the data in the ND4J impl).
However, if you must, yeah, you can use generics here. You've type-varred BaseMatrix, and that means all usages of BaseMatrix must be parameterized. That's the part you messed up in your code. If we go with your plan of a type-parameterized BaseMatrix class and a field of type T, the right code is:
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
}
I wouldn't, however, do it this way (I'd go with having the impl have the field, much simpler, no need to bother anybody with the generics). Unless, of course, you DO have an actual need for that field and it IS part of BaseMatrix's API. For example, if you want this:
public class BaseMatrix<T> {
public T getData() { return data; }
}
then it starts to make more sense. With that, you can write the following and it'll all compile and work great:
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
// no need to write a getData method here at all!
...
}
ND4JDense dense = new ND4JDense();
ND4JMatrix matrix = dense.getData();
But, clearly, this makes no sense if you intend for the ND4JMatrix to remain an implementation detail that users of the BaseMatrix API should probably not be touching.
EDIT: You changed the question on me, later. Now you want the mmul method to take 'self' as argument, effectively: You want the same type to be passed in.
You can sort of do that but it is a little tricky. You need the self-ref generics hack. It looks like this:
public class BaseMatrix<T extends BaseMatrix<T>> {
public abstract T mmul(T other);
}
In practice the only valid value for T is your own class, or at least, that is the intent. This works fine:
public class ND4JDenseMatrix extends BaseMatrix<ND4JDenseMatrix> {
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
.. impl here ..
}
}
As far as I see, you have two issues in your code:
You're not actually overriding the method of the superclass. What you have created is an overload of method mmul. To correctly override the method, the method signature must match, in particular the input parameter must be the same. It's ok to have a subtype of the return type, as Java support covariant. If you instead put one of its subclass, that is overloading. Hope you get the difference. So the correct signature can be the following:
public BaseMatrix mmul(BaseMatrix other) {
...
}
You have not specified the type T, so the compiler cannot know that by assumption is a subtype of BaseMatrix. it can be any type, even Object for example, so you are going to get "method not found" compilation error.

Java compiler not able to infer type on generic chain

As mentioned below (to remark it as I might have explained myself badly):
I want to understand the principle behind this issue so that I can apply that knowledge to the real problem.
ISSUE START
I am working in a system intended to be an abstract library to be used by many subsystems. The idea is to have an standard behaviour extensible by implementations.
My problem is that java compiler is not able to inferr method parameter type, even though it makes no sense since the boundaries are well set on every related generic class/method.
Below there is an example, the minimum example to reproduce the problem. I am aware it looks a bit silly in this example, but that is because of the simplification:
public class Test {
public static void main(String[] args) {
Gen<? extends Base> gen = new HijaGen();
gen.applyTo(Hija.EXAMPLE);
}
private interface Base {
String getName();
}
private enum Hija implements Base {
EXAMPLE;
#Override
public String getName() {
return this.name();
}
}
private interface Gen<T extends Base> {
boolean applyTo(T base);
}
private static class HijaGen implements Gen<Hija> {
#Override
public boolean applyTo(Hija base) {
return false;
}
}
}
Basically it says that applyTo expects a subclass of Base and Hija is not valid, which from my perspective makes no sense.
Thanks in advance.
EDIT:
This code is for a library, so that the solution could not be specifying the type since then it could not be extensible through particular implementations.
I am already aware that if I specify the generic type instead of throwing a type wildcard it will perfectly work. But my question is how is it possible that even though Hija subclasses Base, and method firm requires a subclass of Base it will never compile...
I want to understand the principle behind this issue so that I can apply that knowledge to the real problem.
A Gen<? extends Base> is a Gen of something which extends Base. It applies to some specific type of Base but we do not know which. In practice, this means you will never be able to call applyTo on a variable with type Gen<? extends Base>, except by passing null.
Change your code to
Gen<Hija> gen = new HijaGen();
gen.applyTo(Hija.EXAMPLE);
I suspect you'll probably say you can't do that, because your code is just an example, and the above is not possible in the real code. In which case you will need to give a better example
I think there is a similar problem explained in the docs here and the problem that they propose is to make a helper (or wrapper) to clarify the types. So I guess you can try adding this function:
private static <T extends Base> boolean applyTo(Gen<T> gen, T base){
return gen.applyTo(base);
}
And change the main function as follows:
public static void main(String[] args) {
boolean b = applyTo(new HijaGen(), Hija.EXAMPLE);
}
On the lines of what Carlos has mentioned, there is one more way to resolve this. It can be used if you are sure of the suppliers of the implementation of Gen<T>.
Here, instead of the helper to call applyTo(), we define a factory method to create the instance of the Gen implementation and cast it to Gen<Base>, which in my opinion is safe for all practical purposes. Note that the factory method get() need not be static. The rest of the code remains unchanged from your sample.
public static void main( String[] args ){
Gen<Base> gen = (Gen<Base>) get();
gen.applyTo( Hija.EXAMPLE );
}
static Gen<? extends Base> get(){
/* Create the instance of the Gen interface implementation here. */
return new HijaGen();
}
Explanation
Gen<? extends Base> expects to refer to an instance of an implementation of Gen that uses a type that is either Base or an sub-type of it. Since a "sub-type" can be from one of many possible hierarchies from Base downward (as shown in the picture below), it cannot be sure that the parameter passed to applyTo() method is of the same child hierarchy path and not just a 'relative' with the same ancestral parent Base. That is why it won't allow a call to applyTo() with its reference being of Gen<? extends Base> for a parameter of with reference as Base.
However, when the reference is Gen<Base>, it knows that applyTo() will accept any parameter that is a child type of Base. And hence, it stops worrying about type mismatch.
I have tried to show what I mean by different child hierarchy paths. It is like the case of a family tree.

The right and wrong approach to writing Java Enums

Recently, I've discovered this code of the following structure:
Interface:
public interface Base<T> {
public T fromValue(String v);
}
Enum implementation:
public enum AddressType implements Base<AddressType> {
NotSpecified("Not Specified."),
Physical("Physical"),
Postal("Postal");
private final String label;
private AddressType(String label) {
this.label = label;
}
public String getLabel() {
return this.label;
}
#Override
public AddressType fromValue(String v) {
return valueOf(v);
}
}
My immediate reaction is that one cannot create an instance of an enum by deserialization or by reflection, so the fromValue() should be static.
I'm not trying to start a debate, but is this correct? I have read, Why would an Enum implement an interface, and I totally agree with the answers provided, but the above example is invalid.
I am doing this because the "architect" doesn't want to take my answer, so this is to create a strong argument (with facts) why the above approach is good/bad.
Your Base interface does not declare valueOf and the fromValue method is indeed implemented. I see no reason why this code should not compile. If you are referring to the valueOf call inside fromValue, that is a call of a static method defined for every enum. I would have to agree, though, that the design of it is quite misguided as you need an arbitrary member of the enum just to call fromValue and get the real member.
On the other hand, in a project that I'm doing right now I have several enums implementing a common interface. This because the enums are related and I want to be able to treat them uniformly with respect to their common semantics.
In my opinion this design is wrong. In order to use valueFrom() one has to get an instance of this enum beforehand. Thus, it will look like:
AddressType type = AddressType.Postal.valueFrom("Physical");
What sense does it make?
Your Base interface seems to serve a whole other purpose (if any).
It is probably meant to be a String-to-T-converter, since it generates a T from a String. The enum is simply wrong if it implements this interface (#yegor256 already pointed out why). So you can keep the enum and you can have some AddressTypeConverter implements Base<AddressType> which calls AddressType.valueOf() in its fromString() method.
But don't get me wrong: enums implementing interfaces are NOT a bad practice, it's just this particular usage that is completely wrong.

java generics - parameters cannot be applied to method

I can't seem to figure out why a method call I'm trying to make doesn't work.
I've looked much around SO before asking this, and while there are (many) threads about similar problems, I couldn't find one that quite fits my problem..
I have the following code:
(in file Processor.java:)
public interface Processor
{
Runner<? extends Processor> getRunner();
}
(in file Runner.java:)
public interface Runner<P extends Processor>
{
int runProcessors(Collection<P> processors);
}
(in some other file, in some method:)
Collection<? extends Processor> processorsCollection = ...;
Runner<? extends Processor> runner = ...;
runner.runProcessors(processorsCollection);
IntelliJ marks the last line as an error:
"RunProcessors (java.util.Collection>) in Runner cannot be applied to (java.util.Collection>)".
I can't figure out whats wrong with what I did, especially since the error message is not quite clear..
any suggestions?
thanks.
Both your collection and your runner allow for anything that extend processor. But, you can't guarantee they're the same.
Collection might be Collection<Processor1> and Runner be Runner<Processor2>.
Whatever method you have that in needs to be typed (I forget the exact syntax, but I'm sure you can find it!)
void <T extends Processor<T>> foo() {
Collection<T> procColl = ...
Runner<T> runner = ...
runner.runProc(procColl);
}
Edit:
#newAcct makes an excellent point: you need to genericize (is that a word?) your Processor. I've updated my code snippet above as to reflect this important change.
public interface Processor<P extends Processor>
{
Runner<P> getRunner();
}
public interface Runner<P extends Processor<P>>
{
int runProcessors(Collection<P> processors);
}
You have not made your situation clear and you're not showing us any of the code of the methods or of how you get the objects, so we don't really know what you're trying to do.
Your code is not type-safe. As #glowcoder mentioned, there is no way of knowing that the parameter of Collection is the same as the parameter of Runner. If you believe they are indeed the same, then that is based on code that you're not showing us (i.e. what happens in "..."?)
You have written Processor's getRunner() method with a return type that has a wildcard parameter. This says when run it will return a Runner with a mysterious parameter that it determines and we don't know. This doesn't make much sense and is probably not what you wanted.
Also depending on what you are doing, the runProcessors method could possibly take a less strict bound. For example, perhaps <? extends P> or even <? extends Processor> if you don't need to modify the collection.

Subclassing a generic type, returning instances of the subclass from a method in another class

It was such a simple, brilliant idea. Use the power of Java 5.0 enumerated types to encode details of a data dictionary (attribute name, type, range, units, etc.) and create a type-safe system for setting and reading attribute values (i,.e., attribute AAH is short, ACC is enumerated and should only accept the values ACC001, ACC002, ACC003, etc.).
The hitch is that different attributes have different types (integer, float, text, enumerated), and the behaviors for each type are different. So I create a base class with a type parameter and some abstract methods:
public abstract class GsAttributeValueBase<T extends Comparable<T>> {
protected T m_value;
...
public GsAttributeValueBase(...) {..}
...
public abstract void SetValue(T value) throws IllegalArgumentException;
public T GetValue() { return m_value; }
// etc., etc., etc
}
I then subclass this for each type (basically, I'm trying to fake partial specialization):
public class GsAttributeValueShort extends GsAttributeValueBase<Short> {...}
public class GsAttributeValueLong extends GsAttributeValueBase<Long> {...}
public class GsAttributeValueEncoded extends GsAttributeValueBase<GsAttributeEncodedValueEnum> {...}
...
So far so good. Now I want to basically create a factory method in the attribute enumeration type to return an instance of one of the above subtypes (since each attribute knows its type and range), something like
public GsAttributeValueBase<? extends Comparable<?>> CreateInstance()
{
switch(m_format)
{
case SHORT: return new GsAttributeValueShort(...);
case LONG: return new GsAttributeValueLong(...);
case ENCODED: return new GsAttributeValueEncoded(...);
...
}
}
and call the method as:
GsAttributeValueShort = GsAttributeEnum.AAH.CreateInstance();
This is where I hit a brick wall; I get an incompatible types error on the order of
found : GsAttributeValueBase<capture of ? extends java.lang.Comparable<?>>
required: GsAttributeValueShort
I've tried roughly a dozen permutations on the declaration of CreateInstance() so far (it can't be static, since it relies on information specific to the enumeration instance). I'm about to tear my hair out at this point; I've wasted several days going down this rabbit hole, and need to either get this working today or punt altogether.
I really want to make this work; I think it would be valuable to not just this project but other projects going forward. But Java generics don't behave like C++ templates (something that's been driven home with a vengeance over the past week), and I know I'm missing something vital here, but I can't see what it is.
EDIT
I can't make this work the way I'm envisioning in my head and I've burned too much time on it. Thanks for the suggestions, but I'm going to go ahead and close this down.
EDIT 2
Oh. I can't close my own question. Oh well.
What about:
public <T extends Comparable<T>> GsAttributeValueBase<? super T> CreateInstance() {
...
}
Just use a map and my TypeSafeMap pattern.
Some thoughts on Generics: Generics are meant to make collections type safe. They aren't really intended for complex things like building type-safe classes at runtime. So be mindful and use your tools so that they don't become a burden. If a cast works and you don't understand how the generic construct works (even if you just wrote it), use the cast. Just imagine coming back to this code in half a year and having to fix it.

Categories