I am using a heterogeneous container similar to this one. I can put and receive objects from the container with ease:
Favorites f = new Favorites();
f.putFavorite(String.class, "Java");
String someString = f.getFavorite(String.class);
But there seem to be no easy way to iterate over such container. I can add a keySet() method to the Favorites class and simply return the key set of the internal Map object:
public Set<Class<?>> keySet() {
return favorites.keySet();
}
Now, I would like to iterate over the keys, use the keys to get the associated values, and call some methods on the received objects:
for (Class<?> klass : f.keySet()) {
// f.getFavorite(klass).<SOME_METHOD_SPECIFIC_TO_THE_CLASS-KEY>
}
I thought that I could access the methods of the objects held in my container by calling klass.cast(f.getFavorite(klass)).SOME_METHOD(), but it doesn't work either (meaning, I cannot access any methods except for the Object-related methods).
Let's say, that in my use case I would like to inspect the interfaces of all these objects I iterate over and act accordingly to the detected interface. Let's also assume that I may have dozens of objects of various classes and all of them implement one of three interfaces.
The only solution I can think of is to stuff my code with dozens of isinstance checks, but I would prefer a less cumbersome approach (i.e. checking if a given object implements one of three interfaces).
By trying to call a specific method on each entry, you are basically saying that you know better than the compiler, and that you know each entry has a specific super class.
If you know that's the case, you can use Class#asSubclass to type klass as Class<? extends KnownSuper> so that getFavorite will then return a subclass of KnownSuper (and therefore expose the method):
Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod()
for (Class<?> klass : f.keySet()) {
f.getFavorite(klass.asSubClass(superClass)).callMethod()
}
However, this will obviously give a runtime exception if one of the key classes does not extend KnownSuper. So if the above would be safe, you should parameterize your heterogeneous container to only accept key classes that extend from KnownSuper in the first place.
If not all entries will be of this type, you could also check first if the key is suitable when iterating:
Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod()
for (Class<?> klass : f.keySet()) {
if (superClass.isAssignableFrom(klass)) {
f.getFavorite(klass.asSubClass(superClass)).callMethod()
}
}
Just go through this simple example
Say you have below Favorites class definition
public class Favorites extends HashMap<String, String> {
}
Here is the test class
public class TestGeneric {
public static void main(String[] args) {
Favorites f = new Favorites();
f.put("test", "test");
for (String test1 : f.keySet()) {
f.get("").charAt(index)// you will see all string specific method as compiler knows in advance what object map going to contain
}
}
The moment you change Favorites extends HashMap<String, String> to Favorites extends HashMap you will just object specific methods as compiler does not know in advance which object Favorites is going to put in map
Related
I am writing a class that takes in a parameterized type, which I am trying to parameterize.
So I have a User object which has an ID. I am making ID a parameterized type. I have a class called Router that needs to provide one method T route(List<T>);, where T extends User.
Within Router I have some utility methods where I need to group by an ID within User, which is also parameterized. So User looks like User<K>, where K is the type of ID. So I would have a method that looks like the following within Router:
public T route(List<T> listToRoute) {
Map<K, Double> someUtilityMap = groupValueById(listToRoute);
// apply some logic
return chooseFinalCandidate(someUtilityMap);
}
Currently I have:
public class Router<K, T extends User<K>> {
Is there a cleaner way to get and reference K within Router without the callers having to provide it explicitly in instantiation? Can I somehow just give T and then use K in the Router implementation?
I need to reference K explicitly in code, so something like:
Map<K, Double> groupValueById(List<T> routingCandidates) {
What I would like to do is something like:
new Router<User<Integer>>();
as opposed to:
new Router<Integer, User<Integer>>();
I would suggest you to change the signature or your class to public class Router2<K>.
Currently, I understand, you have something like
public class Router<K, T extends User<K>> {
Map<K, Double> groupValueById(List<T> routingCandidates) {
return null;
}
}
Then call it like
List<User<Integer>> list = new ArrayList<>();
Router<Integer, User<Integer>> router = new Router<>();
Map<Integer, Double> map = router.groupValueById(list);
You can change it to something like
public class Router<K> {
<T extends User<K>> Map<K, Double> groupValueById(List<T> routingCandidates) {
return null;
}
}
and call it like
List<User<Integer>> list = new ArrayList<>();
Router<Integer> router = new Router<>();
Map<Integer, Double> map = router.groupValueById(list);
Although it might seem that we only move the problem to another place, it makes it much simpler to use the class, because you do not need to write down the generic type parameters when using the method.
I think there are two concepts here, that have to be kept separated:
The type parameter of the class
The type that the class operates on
The only varibale type that is not known in advance and that has to be filled in is K. When you know K, you can derive User<K> from it. User is always the same. So this class should have only one type parameter: K. This is sufficient for defining the concrete classes.
The class operates on objects of type User<K>. You try to express this by type parameters, but this is not what generics are made for. I do not know of a way to capture the K from User<K> and I think it is not necessary here. It would only make the definition more complicated than necessary.
Possibly duplicate, I have an abstract class called FormField which contains some common properties like field value, field label, etc.
My application renders fields dynamically based on an APIs result. So, I can get a JSON which says fieldX of type String, fieldY of type Date, etc. Based on the type I want to automatically render the correct field. I was already able to abstract the logic using an abstract class with static blocks. The abstract class has code like:
// Common fields
public String label;
public String value;
public static Map<String, Class> fieldTypes = new HashMap<>();
static {
FormField.fieldTypes.put("String", StringField.class);
FormField.fieldTypes.put("Date", DateField.class);
}
I originally wanted to put the static block in StringField, DateField to add themselves automatically to the fieldTypes array in their parent FormField abstract class but that didn't work since I do not explicitly call these field type classes anywhere so their static blocks never get called at all. I figured the alternative would be to just initialize each inside the FormField static block.
The way the app works, it fetches the data from the API and for each field it calls a create method which takes the type identification string i.e. String, Date and based on that my FormField class initializes the code using this:
public static FormField create(String type, String label) {
Class aClass = fieldTypes.get(type);
if(aClass == null)
return null;
FormField field = null;
try {
field = (FormField) aClass.newInstance();
field.label = label;
return field;
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
}
}
Then it calls the render method which renders the UI and does further operations. I want to eliminate the static block and want hashmap to fill itself automatically whenever I create (not initialize) a new concrete class that extends it. This would help me to create new concrete classes whenever my business logic needs it i.e. tomorrow I can add any new field type such as photo and just write the specific logic for that rather than having to add a line to the static block each time. I wouldn't mind a better solution which eliminates fieldTypes hashMap too. I know there's some way through reflection to go thro the entire 'fieldTypes' subpackage and initialize one after another but I don't want that (nor do I know how it would be coded) since I feel is bad practice. Any better solutions to this problem?
I can think of two solutions for this problem:
1) This requires an external lib: https://github.com/ronmamo/reflections
Using this libray you can get all instances of a parent class, I assume Field as follows:
Reflections reflections = new Reflections("your.project.fields");
Set<Class<? extends Field>> allClasses =
reflections.getSubTypesOf(Field.class);
For your case, whenever you introduce a new class to your codebase, this reflective code runs, discovers the class and use it accordingly.
2) Whenever you introduce a new class, you update a file, which contains all BlahField classes. You can initialize your map using this class but, I have to admit that this is less intriguing.
My Task is to write a unit test for a method findSubClassImplementation that returns an instance for a given Class object. The method signature looks like this:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception
Internally the method checks wether the supplied Class object belongs to a set of known classes and then returns an instance of that class:
if (Subclass.class.equals(cls))
return (T) new Subclass(args);
If the class is not known, an Exception is thrown. This code is given
I tried to load all Classes inheriting from SuperClass via Reflection and then pass them as argument to findSubClassImplementation:
Set<Class<? extends SuperClass>> subTypesOf = reflections.getSubTypesOf(SuperClass.class);
Class<? extends SuperClass> clazz = subTypesOf.iterator().next();
SuperClass instance = findSubClassImplementation(clazz);
I then use a Debugger to step into the method, and I can see the line of code where
if (Subclass.class.equals(cls))
returns false, although cls = Subclass.class
I assume what happens is this: Class does not implement equals, thus equals of Object is used, that compares with "==". As reflection uses a different ClassLoader than is used in findSubClassImplementation the two class Objects are different. Is this assumption correct?
Is it possible to get the other Class object for a class that I have loaded with Reflection? Do you have another idea how to deal with this problem?
ANSWER:
Turns out I am not very good at reading: The hirarchy is in 3 levels: SuperClass --> IntermediateAbstractClass--> Subclass. The comparison is always to the intermediate abstract class:
if (IntermediateAbstractClass.class.equals(cls)) return (T) new Subclass(args);
Thus my question wasn't very accurate or precise - I am sorry if you feel like I wasted your time. I'll mark Michael Wiles answer as the correct one, because his advice pushed my to discover my missunderstanding. Thank you!
There must be something that is different about the classes...
You say that Subclass.equals(otherSubclass) returns false we need to ascertain why this is the case.
Check the name of each class for equality and then check the classloader of each class for equality.
Based on your provided code to do the reflection there is nothing here to sugggest that these classes loaded by "Reflection" are in fact loaded from different classloaders.
Furthermore try all sorts of classes, maybe there is something unique about that particular class that causes the behaviour.
One suggestion to try would be to add Integer to the subclass set and then pass in Number to the method...
Maybe you don't need to check what class is cls, since cls already contains all the information you need. Try simply with
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
constructorParamTypes[i] = args[i].getClass();
}
return cls.getConstructor(constructorParamTypes).newInstance(args);
}
Or in the Java 8 way:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = Arrays.stream(args).map(Object::getClass)
.toArray(size -> new Class<?>[size]);
return cls.getConstructor(constructorParamTypes).newInstance(args);
}
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 am just learning Java, but my question is both Java-related and general.
My situation is this: I have a method that I would like to use commonly by several classes, through inheritance. Inside the method block, I need to declare a variable of the calling class, create objects from it that are housed in an ArrayList<> ("array") of the calling class, and send the output through an ObjectOutputStream ("output") to a serialized file.
I have the following classes:
CustomerInternalFrame.java, which maintains an "array" of serialized Customer.java using an ArrayList of type Customer.
ContractorInternalFrame.java, which maintains an "array" of serialized Contractor.java using an ArrayList of type Contractor.
VendorInternalFrame.java, which maintains an "array" of serialized Vendor.java using an ArrayList of type Vendor.
In each of these InternalFrame classes, I have the following method, addRecords (replace "Customer" with the appropriate class, either Customer, Contractor, or Vendor):
private void addRecords() {
// object to be written to the file
Customer record;
// loop until end of array
for (Customer element : array) {
// check for closed streamer and invalid entries
try {
// create a new object from current fields
record = new Customer(
element.getName(),
element.getLastName(),
element.getAddress1(),
element.getAddress2(),
element.getCity(),
element.getState(),
element.getZip(),
element.getPhone(),
element.getCell());
// write new record
output.writeObject(record);
} // end try
... (catch blocks)
} // end for
} // end method
I have thought hard and searched long for a way to programmatically change the word "Customer" in the above, so that I can declare a single method (or class) addRecords() and have each of the three InternalFrame classes use it, without having to duplicate code. I of course cannot replace the word "Customer" with "Object" in all cases, because "Object" does not have my methods getName(), getAddress1(), etc. I also cannot replace "Customer" with an "Object()" array, for the same reason. (In other words, using arrays--the normal solution--does not work in this case, because I would have to use a superclass array and then downcast it, but downcasting it requires declaring the originally-named class in the first place. So an array is just a vicious circle in this case.)
I realize having three separate addRecords() methods allows me to change whatever fields I am recording in the respective file, since Customer, Contractor, and Vendor may well have different field sets. But I have other situations that are similar, where the things I am doing in the code are identical, but called on by different classes (such as similar event handlers), and it sure would be nice to be able to know if something like this can be done at all.
So, is there any way to change a variable type, including by passing one in to a method or constructor, so that several classes can use the same code to create objects of those specific classes?
Make your base class generic like so:
public abstract class InternalFrame<T> {
protected abstract Collection<? extends T> getElements();
protected abstract Serializable getRecord(final T t);
public void serialize(final File file) {
try (final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
for(final T t : getElements()) {
oos.writeObject(getRecord(t));
}
} catch (IOException ex) {
//handle
}
}
}
And then in your extending class you just need to implement the abstract methods
public class CustomerFrame extends InternalFrame<Customer> {
#Override
protected Collection<? extends Customer> getElements() {
return array;
}
#Override
protected Serializable getRecord(Customer element) {
return new Customer(
element.getName(),
element.getLastName(),
element.getAddress1(),
element.getAddress2(),
element.getCity(),
element.getState(),
element.getZip(),
element.getPhone(),
element.getCell());
}
}
And you would call the serialize(final File file) method to write the records to a File.