I'm learning about Factory Pattern and I am using THIS article as a source. In it, there is this piece of code:
class ProductFactory {
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass) {
m_RegisteredProducts.put(productID, productClass);
}
public Product createProduct(String productID) {
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
I'm having a hard time figuring out how createProduct() method works. When I'm trying to use this code I get Non-static method `getDeclaredConstructor(java.lang.Class<?>...)' cannot be referenced from a static context error. productClass variable is declared but never used so there is clearly something wrong with the code but I can't figure what exactly. I checked similar questions on SO but don't know how to repurpose them for this case. Reflection is a really confusing subject for me.
My questions:
What is wrong with this code?
Why it is passing new Class[] { String.class } in getDeclaredConstrutor() method and what does it mean?
Why is it passing Object array in newInstance() instead of just single object?
Question 1
There are several things wrong about this code.
It just does not compile because cClass member is missing. Logically, It should be productClass.getDeclaredConstructor instead.
Raw HashMap is used instead of generically typed Map<String, Class<? extends Product>>. Also raw typing for Class and Constructor.
The naming m_RegisteredProducts does not respect Java naming conventions.
Question 2
new Class[] { String.class } arg aims to retrieve the constructor with a single String arg, for example public Product(String id).
It could have been retrieved with just
productClass.getDeclaredConstructor(String.class);
because it is not mandatory to create arrays for varargs.
Question 3
This array arg just looks like a blunder. The constructor instance is retrieved for one with String arg, but it is passing something else to instantiate it. So inevitably there will be an exception thrown.
Conclusion
There are too many wrong or inaccurate things in this example and probably in the article itself. I'd recommend choosing another one.
Related
I am currently making a library which is an utility for me to handle something which is not associated with the question (I am implicitly not saying the subject because it is not really important), however it does use reflection.
I am retrieving all declared and inherited methods from a class, which currently works fine and is not the issue. But the thing is, I need to do this as well for sub-classes since those inherit over like methods do (however you cannot override those like methods).
The problem that I am facing that it will use the same algorithm but there will be on difference, instead of calling clazz.getDeclaredMethods() I need to call clazz.getMethods. What is the best way too approach this, and I kind of need to return Class[] and Method[] in the method signature as well.
Normally I would look for a shared superclass, but in this case I prefer to the have Class[] and Method[] accordingly. For starters, I did some research and found some shared superclasses:
GenericDeclaration
AnnotatedElement
Since I need both Class[] and Method[] arrays I am thinking something
like generics, so the method would look like:
public static <T extends GenericDecleration> T[] getT () {
}
As mentioned by dasblinkenlight this will not work since the method doesn't take any arguments and cannot check whether to retrieve Class or Method objects.
But how would I detect whether I need to call getDeclaredMethods or getDeclaredClasses?
What is the best approach on how to do this without duplicating a lot of code? I really tried to explain myself here, but if it is still unclear what I am doing please feel free to ask away!
Thank you very much in advance!
After messing around with this, I have found a solution that totally fits my needs. This is a combination of generics and #dasblinkenlight's solution, like so:
public interface DeclExtractor<T extends GenericDecleration> {
public T[] extract (Class clazz);
public Class<? extends T[]) getGenericClass ();
DeclExtractor<Method> methodExtractor = new DeclExtractor<Method>() {
#Override
public Method[] extract (Class clazz) {
return clazz.getDeclaredMethods();
}
#Override
public Class<? extends Method[]> getGenericClass () {
return Method[].class;
}
}
// Same for Class
}
Now the method which also will return the correct type so you dont have to manually cast all GenericDeclaration to your original object type. My issue was that I used a collection for it and not the correct array:
public <T> T[] getAll (final DeclExtractor<T> extractor, Class<?> clazz) {
T[] declaration = extractor.extract (clazz);
//.. The algorithm..
// Return an instance of a collection as array (I use a set in my implementation)
final Object[] objects = myCollection.toArray();
return Arrays.copyOf(objects, objects.length, extractor.getGenericClass());
}
Technically you do not need the getGenericClass method in the interface, but I am using extract directly in a loop so I cannot pull the class of that, however, you can.
Hopefully this helps someone in the future :) Thanks again to #dasblinkenlight for the inspiration!
Your getT needs to get some input in order to decide what to do.
What about a method which can takes an enum as argument to determine whether it needs to get classes or methods? (from a comment)
There is a better approach: define an interface that performs the appropriate extraction, and make two instances of it - one for extracting classes, and one for extracting methods:
public interface DeclExtractor {
GenericDecleration[] extract(Class cl);
final DeclExtractor forClasses = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted classes
}
};
final DeclExtractor forMethods = new DeclExtractor() {
public GenericDecleration[] extract(Class cl) {
// make an array of GenericDecleration from extracted methods
}
};
}
Now you can rewrite your getT to take an "extractor", like this:
public static GenericDecleration[] getT (DeclExtractor extractor, Class cl) {
...
// When it's time to get components of the class, make this call:
GenericDecleration[] components = extractor.extract(cl);
...
}
To initiate a call to getT, pass DeclExtractor.forClasses or DeclExtractor.forMethods:
GenericDecleration[] c = getT(DeclExtractor.forClasses);
GenericDecleration[] m = getT(DeclExtractor.forMethods);
I would like to know if there is a way to do something like this in Java:
Integer a = new Integer(2);
a.getClass() newVariable = new Integer(4);
My question is can I declare the type of a new variable by using a variable?
It is not possible to specify the type by retrieving it from an other variable.
Note that the reflection tutorial of Oracle provide some methods that would simulate it. It will allow you to instantiate an object by specifying it type as a class. But that won't allow you to first specify the object type by retrieving it from the variable.
You might want to have a look at generics which would probably help you fix the hidden problem that made you ask this question.
A simple example would be
public class Foo<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Note that T stands for Type as per the documentation.
#param the type of the value being boxed
So you can give any type.
You can also specify the extends of the type, which kind of give you some security.
class Foo<T extends Integer>
No, you cannot base the type of a variable on the type of another variable like that.
Depending on your real goal, you might be able to use Java's generics to get around your reason for feeling you want to do that, but it depends a lot on what your real end goal is. For instance, if this is all in class Foo, you could parameterize it, and then use the parameter in both places:
class Foo<T> {
public method doSomething() {
T a = /*...*/;
T newVariable = /*...*/;
}
}
Then:
Foo<Integer> f = new Foo<Integer>();
...results in an f with a doSomething that works with and returns Integers.
Note the /*...*/ after the = in the above: I can't do new T() there, which is a famous limitation of Java's generics. The values for a and newVariable would have to come from somewhere (arguments to the method, for instance, or data members, etc.).
More about generics here, again depending on whether they really help with what you're ultimately trying to do.
Currently developing a code smell detector for a uni assignment. I have made an abstract CodeSmell class, with two concrete subclasses - ClassLevelSmell and MethodLevelSmell. The CodeSmell class has a protected field of type SmellType. A sample constructor is as follows:
public ClassLevelSmell(ClassDefinition classDef, SmellType type){
smellyClass = classDef;
this.smell = type;
}
SmellType is an enum I defined, which looks like this:
public enum SmellType {
LONG_CLASS, LONG_METHOD, PRIMITIVE_OBSESSION, LONG_PARAM_LIST}
I then have a SmellDetector object, with numerous methods that compare the statistics of analyzed classes and methods (such as their number of lines, number of primitive declarations etc) and creates a new CodeSmell object if a smell is found. So my code for this looks like this:
private void detectLongClass(ClassDefinition classDef) {
if(classDef.getNumLines() > 250){
smells.add(new ClassLevelSmell(classDef, LONG_CLASS));
}
}
Each SmellDetector object has a field smells, an ArrayList of CodeSmells. However, I'm getting a compiler warning in eclipse when I try to pass the SmellType LONG_CLASS into the constructor for the ClassLevelMethod, telling me "LONG_CLASS cannot be resolved to a variable". Am I making some mistake with the use of Enumerated types? What do?
To reference enum values you either need to use the qualified form with the class name or use static imports. So either make it:
smells.add(new ClassLevelSmell(classDef, SmellType.LONG_CLASS));
or do this:
// at the top of your file:
import static packagename.SmellType.*;
smells.add(new ClassLevelSmell(classDef, LONG_CLASS));
Try this:
smells.add(new ClassLevelSmell(classDef, SmellType.LONG_CLASS));
I'm trying to solve the following issue in reflection. I've a POJO which kind of acts as a metadata for the method signature in TestResponse class. TestResponse has a setDate() methid which takes a Date parameter. I'm trying to make this is a generic code which can accept any method and its signature to set in the response. What I'm not able to figure out is how to set the parameter Class while calling getMethod() based on the input. The input tells me to set the parameter as Date, but not sure how to achiever that.
Here's my sample code. Ofcourse, the mdi.modifier.getClass() is wrong since it'll get String.class instead of Date.class.
TestResponse response = new TestResponse();
Object val = "test";
MDIBase mdi = new MDIBase("setDate", "Date");
Method m = response.getClass().getMethod(mdi.method, mdi.modifier.getClass());
m.invoke(response, new Object[] { val });
Here's MDIBase
public class MDIBase {
public String method;
public String modifier;
public MDIBase(String method, String modifier){
this.method = method;
this.modifier = modifier;
}
Any pointers will be highly appreciated.
Thanks
I'm not sure I fully understand you, but if I do, you want to be able to pass in a class name for the parameter?
In order to do that, instead of passing in "Date" pass in "java.util.Date" (this is known as the fully qualified class name) and then instead of getClass call
response.getClass().getMethod(mdi.method, Class.forName(mdi.modifier));
That will dynamically load the class that has the fully qualified name you supplied.
Is that what you're looking for? If not, give me some more information and I'll take another stab at it.
I have a method that usually takes an item from a list and has a signature of:
myMethod(T item)
I want to use this method but I know what I am sending the method.
SpecificItem myItem = new SpecificItem();
myMethod((T) myItem);
This doesn't sit well with me. Is this a sign of bad code?
myMethod is defined in a generic class, somewhat like:
public class MyClass<T> {
T myItem;
public void myMethod(T item) {
// do Something with item
}
public T myOtherMethod() {
myMethod(myItem); // casting is not necessary
return myItem;
}
}
If you instantiate this class, you exchange the variable type T with a real one:
MyClass<SpecificItem > concreteClass = new MyClass<SpecificItem >();
And if you call myMethod on this instance, you have to provide a SpecificItem, because SpecificItem is the generic type for this instance.
(I'm not sure it my post answers your question, please comment so I can improve it)
It's better that you code to interface. For example :
In myMethod :
<T extends <? super Item>> void (T item);
This tells compiler to only accepts a generic type of T which is an implementation/extention of Item interface/class. This will make sure that given input is in correct type. Compiler guarantees it.
In main class :
Item myItem = new SpecificItem();
Code given above is the best practice. Get used to it. But (i discourage this) you can code like this too :
SpecificItem myItem = new SpecificItem();
You can read Java source code. For example in class java.util.Collections. In method sort(List) you may notice that Joshua Bloch makes sure that given input is always in correct format. To give it a try, do this :
public class Class1 {
public static void main(String[] args) {
List<Class1> list = new ArrayList<Class1>();
Collections.sort(list);
}
}
Above code will produce compilation error. To fix this compilation error Class1 must implement interface Comparable. This maintains the precondition of method sort(List) which assumes that given input is a List of Comparable.
Oh i almost forget about your question. Actually it's not a bad code since it works. I just want to tell you that there is a better way to do that.
You might be looking for something like this:
class C<? extends T> {
public void myMethod(T myItem) {
...
}
}
The way you call the method looks strange. If you have declared your generic method as
public <T> void myMethod(T item);
the compiler knows, that T is some abstract type and you shouldn't need to cast an input parameter to it. Just make sure, that T is not declared as some specific type in your code.
upd: look here for an example: http://www.java2s.com/Tutorial/Java/0200__Generics/Usinggenericmethodstoprintarrayofdifferenttypes.htm
Probably better way would be to make SpecificItem a subclass of T or make T an interface and have SpecificItem implement it.