I have a situation where I use reflection to create objects at run-time based on their fully qualified class names. All the objects extend the same abstract class, so their general type is known at compile time but the concrete implementation is determined by the class name supplied at run-time.
The abstract class provides one static method named create, that takes the class name and other parameters with which to construct the concrete object. Each Response has an actual type A and a storage type S. The actual type is the "proper" representation of the data in Java and the storage type is the thing that gets stored in the database. E.g. A might be a Date object and S might be the same Date objected converted to a Long for storage in SQLite.
Here's a simplified representation:
public abstract class Response<A, S> {
public Response(String clazz, Object value, boolean actual) {
this.clazz = clazz;
if (actual) {
actualValue = (A) value;
} else {
actualValue = toActualValue((S) value);
}
}
public static Response create(String clazz, Object value) {
//create response by reflection
return response;
}
}
This was working okay until I now when I have to deal with the fact that in addition to the two parameters that each Response implementation takes, some Response implementations now need to take additional parameters.
These additional parameters cannot be passed via setter methods as they are typically used in the package private method toActualValue() that is called from within the abstract Response constructor.
I've considered using the Builder pattern to handler the optional parameters, but then I would need a way to determine which Response implementations take which parameters - and I can't think of a clean way to provide that information. Maybe I am thinking about this entirely wrong. Any helpful insights or suggestions will be appreciated.
Have you considered using the arbitrary number of arguments?
public TestClass(String clazz, Object value, boolean actual, Object... parms) {
this.clazz = clazz;
if (actual) {
actualValue = (A) value;
} else {
//actualValue = toActualValue((S) value, parms);
}
}
https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
Related
I'm using an API from an external Maven dependency with the following signature:
public <T> T get(String key, Class<T> responseType)
the API returns an object of type T for a given key from a key value store.
In my application there're several object types which can be returned, for example: Product, Customer etc.
I'd like to wrap the external API into my service which will receive a key and will return the object found. I can't figure out though how to return the object type from the service. Below is my attempt:
public class MyService {
public <T> T get(String key, String objType) {
Class clazz = null;
if (objType == "Customer") {
clazz = Customer.class;
} else if (objType == "Product") {
clazz = Product.class;
}
return externalApi.get(key, clazz); // doesn't compile
}
}
This code doesn't compile because of Incompatible types: Object is not convertible to T error.
How can I properly pass responseType to externalApi.get and return the correct type without reflection?
As the OP may have guessed, this is inherently impossible.
If the call site for get could do anything useful to preserve the returned type, T, then it would know the type anyway and could supply the correct class (providing this is transitively propagated through call sites).
(Also note, the code uses == for String instead of equals or switch.)
I am trying to make an enum list, and have an abstract method defined in the enum, which each enum value implements. The problem I am facing is that the abstract class has a generic return type but I want each enum value to return a concrete type.
I'll give an example:
public enum Attributes {
name {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Name getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
},
address {
#Override
public void createAttribute(Person person) {
//Do some validations
//Save in some storage
}
#Override
public Address getAttribute(Person person) {
// Validations
// Retreive from storage
return new Name("test");
}
}
public abstract Object getAttribute(Person person);
public abstract void createAttribute(Person person);
}
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety. How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
Now I wanna call this as,
Arrays.stream(Attributes.values()).forEach(r -> {
r.createAttribute(person);
}
final Address address = Attributes.address.getAttribute(person);
final Name name = Attributes.name.getAttribute(person);
So now whenever I need to add a new attribute I don't want to write create methods for it in the Person class every time. I just add it to enum and it gets created. But now since I have the create method in the enum, I also want the getAttribute to be present here.
Here the issue is that I would need to do typecasting to get the concrete object which is not recommended and I don't get any type of safety.
You're right. Given an enum type E with an associated enum constant C, the type of the expression E.C is E. Java provides no mechanism for naming or representing a narrower type for that expression. One of the implications is that although an enum instance can implement methods with covariant return types, the covariance is not visible outside the instance. If you depend for some purpose on the narrower return type of one of those instances' methods, then casting is your only alternative.
And you're right that such casts are not type safe. They cannot be checked by the compiler, and in practice, you as programmer can get them wrong. But the information to perform a compile-time check is not expressed by the language, so there is no scope for a workaround in the language as it is defined today.
How Should I go about so that using the enum value I can get my concrete object instead of the generic one.
You should choose an altogether different approach, not involving an enum.
If you stuck with the enum then you would have to adopt an approach that relies on the enum instances to perform any tasks that depend on their own particular characteristics. Because you ask so persistently, one possibility would be to implement a variation on double dispatch. Instead of a getObject() method, you would have something like
void acceptReceiver(AttributeReceiver r, Person p);
paired with
public interface AttributeReceiver {
default void receiveName(Name name) { /* empty */ }
default void receiveAddress(Address addr) { /* empty */ }
}
Of course, the enum instances would have to implement acceptReceiver appropriately.
You would probably want to use that a little more directly than just to retrieve attributes, but you could use it to retrieve attributes something like this:
class Example {
Name name;
Address address;
void retrieveAttributes(Person person) {
AttributeReceiver receiver = new AttributeReceiver() {
public void receiveName(Name n) { name = n; }
public void receiveAddress(Address a) { addr = a; }
};
Attributes.name.acceptReceiver(receiver, person);
Attributes.address.acceptReceiver(receiver, person);
}
}
But that's awfully roundabout when you have the alternative of using (just) methods, whether on Person or even on some non-enum utility class. I continue not to see any advantage to involving an enum here. I think your code overall would be more complex and harder to understand and maintain with enums than without.
The root issue is that you are abstracting away details that you actually care about. That's a deep design flaw. You can program your way around it, but it would be better to choose a more appropriate level of abstraction in the first place.
I have a class Data that stores a single piece of data in form of a String, it also stores type to which this data should be converted, the type is stored as an enum constant (to allow only for specyfic types). Data objects that describe one item are stored in DataItem class. Intention is that the Data object corresponds to a field in a table and DataItem represents a full row. It is also important to mention that Data objects are created from DataTemplate class which specifies where to look for this kind of data and its type (so the type of each Data should be known at compile time).
I want this program to be very flexible when it comes to database choice so method "save" comes from Storage interface that allows to use any type of storage (file/RDB/Document database...) after implementing it.
I wonder about a good way of converting those String values from Data objects to the appropriate types so I can save them to database. An easy way would be to use something like this:
public void save(DataItem dataItem) {
for (Data data : dataItem) {
if (data.getType() == DataType.BOOLEAN) {
// Convert to String to boolean and save
}
else if (data.getType() == DataType.DOUBLE) {
// Convert to String to double and save
}
...
}
}
But it's not a very good design as I would have to repeat this code for each implemenation of save. It also violates open/closed principle, because if I add some new types I would have to modify all the save methods.
I have also tried using generics or reflection but none of those implementations was satisfactory.
One generic solution that I came up with would require user to to use one of the provided enum constants but then instead of storing enum constant, Data class would store Class instance of corresponding type. That way I stil control what types can be used and get compile time errors if wrong class is picked. This would allow me to implement converter method that works this way.
public <T> T convert(Data data, Class<T> clazz) {
if (data.getType() == Boolean.class) {
// Convert String to Boolean
return (T)
}
else if (data.getType() == Double.class) {
// Convert to String to Double
return (T)
}
...
}
Then I could also use similar pattern and store converting methods in DataType enum alongside allowed data types. Using abstract method that every type would have to specify. Something like:
public enum DataType {
BOOLEAN(Boolean.class){
#Override
public <T> T convert(Data data, Class<T> clazz) {
return clazz.cast(Boolean.parseBoolean(data.getContent()));
}
},
DOUBLE(Double.class){
#Override
public <T> T convert(Data data, Class<T> clazz) {
return clazz.cast(Double.parseDouble(data.getContent()));
}
},
...;
...
public abstract <T> T convert(Data data, Class<T> clazz);
}
In that case I would just have to modify the DataType enum when adding a new type, provided that underlying storage has a method accepting all of the allowed types.
So finally, my questions:
1. Is there a better way to do this?
2. If no, which design should I choose?
You could store your conversion functions in a Map<Class<?>,Function<String,?>> map. Look up the conversion function based on the Class. Add new functions to the map as new types are created.
Map<Class<?>,Function<String,?>> map = new HashMap<>();
<T> T convert(String data, Class<T> clazz) {
return (T) map.get(clazz).apply(data);
}
Alternately, you can create your own DataType class, and create singleton instances for each type, and add appropriate conversion methods to each singleton:
public abstract class DataType<T> {
<T> T fromString(String data);
}
public final static DataType<Boolean> BOOLEAN = new DataType<Boolean>() {
Boolean fromString(String data) {
...
}
};
// ...
Data data = ...
Object value = data.getType().fromString(data.getContent())
You can add additional fields and methods to DataType, as appropriate.
You could create an Interface (Savable) that each of your savable classes would need to implement with 2 interface functions called toSaveString and initFromSaveString.
Then when load from the DB you would just need switch statement to determine which class to load the data to.
I'm trying to define a generic wrapper method for Android's SharedPreferences, for getting\setting in a more convenient way a list of predefined parameters.
Initially I defined an enum of all supported types (String, Int & Bool in my case), each one of them is associated with its corresponding class:
public enum ParamType {
String(String.class),
Int(Intent.class),
Bool(Boolean.class);
private final Class paramClass;
ParamType(Class paramClass) {
this.paramClass = paramClass;
}
}
Then I defined the enum of the known parameters I use, with the associated type of each one:
public enum Param {
FirstParam(ParamType.Bool),
SecondParam(ParamType.String),
ThirdParam(ParamType.Int);
Param(ParamType paramType) {
this.paramType = paramType;
}
private final ParamType paramType;
}
Then I want to have a generic method, that by the given parameter, will know to return the appropriate type:
public static <T> T getParamValue(Param param) {
}
However, I'm not sure how to implement this method and if it's actually possible, since the generic T param is not passed in the signature above.
It is a OVERENGINEERING, don't do that. You can create interface for saving your customobject and loading it and implement it for SharedPreferences and database. But it is not neccessary to create generic for every integral type, if there is three - five types.
Given the following interface:
public interface GenericInterface<T> {
T getValue();
void setValue(T newVal);
}
And the following impl:
public class FixedImpl implements GenericInterface<String> {
String value;
public FixedImpl(String value) {
this.value = value;
}
#Override
public String getValue() {
return value;
}
#Override
public void setValue(String newVal) {
value = newVal;
}
}
I want to be able to determine that in the case of FixedImpl, String.class is the value for GenericInterface.T by interrogating FixedImpl.class.
My current idea:
Find a method name in GenericInterface that returns a <T> - in this case, there's "getValue".
Go through all the methods declared in FixedImpl.class with the same name, and collect all the different return types.
The return type farthest from Object is my value for GenericInterface.T.
But there's a couple of issues with this process:
It will only work for generic types containing a method that returns <T>. You can't safely do the same trick using setValue(T), because method overloading by parameter / arity is possible to do in Java source. It only works for T getValue() because overloading by return value isn't (unless I'm mistaken).
It might have weird interactions with Java 8 default methods, or a generic method implementation in a (still generic) possibly abstract superclass.
It's kinda kludgey.
Can anybody point me to an easier / more surefire way to get the same information? I can't seem to find one, but I thought I'd ask the superior intellects of the toobs :)
NB: If you're wondering why I'd need this, it's because I want to programatically construct mocks of container classes with similar hard-coded type parameters, but POJO values rather than simple Strings.
EDIT: I eventually worked out the following solution (before seeing #stony-zhang's):
public static <G> List<Class> getConcreteTypes(Class<? extends G> implClass, Class<G> genericClass) {
List<Class> concreteTypes = new ArrayList<Class>();
for (Type type : implClass.getGenericInterfaces()) {
if (!(type instanceof ParameterizedTypeImpl)) continue;
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) type;
if (parameterizedType.getRawType() != genericClass) continue;
for (Object arg : parameterizedType.getActualTypeArguments()) {
if (!(arg instanceof Class))
throw new IllegalArgumentException("Class " + implClass + " not concrete for generic type " + genericClass);
concreteTypes.add((Class) arg);
}
}
return concreteTypes;
}
You can get the the class of T by the following way, in the interface add a method getMessageClass(), and in the FixedImpl add the implemented method,
#SuppressWarnings("rawtypes")
public Class getMessageClass() {
int index =0; //In the case, you only have a generic type, so index is 0 to get the first one.
Type genType = getClass().getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
throw new RuntimeException("Index outof bounds");
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}
In you case, if you have multiple subclass, to use it, create one abstract class to implement the interface GenericInterface, and then the all subclass extends from the new abstract class,
public class abstract abstractImpl<T> implements implements GenericInterface<T> {
#SuppressWarnings("rawtypes")
#Override
public Class getMessageClass() {
...............
}
}
Remember type erasure. At runtime, there is no type information about your generics anymore, unless you specify it yourself. And this is what you should do. Add this to your interface:
Class<T> getTypeOfT();
And add this to your FixedImpl:
#Override
public Class<String> getTypeOfT()
{
return String.class;
}
That way, you can always call getTypeOfT() on your GenericInterface<T> implementations and find out what type you are dealing with.
I don't think that you will be able to get reliable result because of Type Erasure:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Your approach of of using the types of objects returned may at first seem alright, but beyond the issues you have pointed out there is no way (at runtime) to know if The return type farthest from Object is my value for GenericInterface.T.
My suggestion would be to use some kind of configuration XML which could be generated at build time based on the java source (using a build tool such as Ant), which would in turn be used to create Mock objects, or you could simply generate the tests based off the source at buildtime.
If you don't mind changing your runtime code for the purposes of testing, Jan Doereenhaus' answer suggests a simple hard-coded mechanism for retrieving the type
EDIT:
Consider the scenario:
public class FixedImpl implements GenericInterface<SomeClass> {
#Override
public SomeClass getValue() {
return new SomeClass();
}
}
public class FixedImpl2 extends FixedImpl {
#Override
public SomeClass getValue()
{
return new SomeSubClass();
}
}
From this example, you can see that the sub class of FixedImpl is able to return a subclass of T (which is further down the inheritance hierarchy from Object)