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.
Related
This class displays informations:
// display line numbers from a file
display(getLineNumber(myFile));
// display users from DB
display(getUsersName(myDBRepository));
etc...
I wanted to make a generic interface, so I can externalize the code that display information.
Then I could do something like:
myInformationElements.stream().forEach(e -> display(e.getValue());
Here is what I have so far (not working):
public interface InformationElement {
public <T> String getValue (T param);
}
public class NbFileLineInformationElement implements InformationElement{
#Override
public <File> String getValue(File param) {
return *same code as in getLineNumber(myFile)*;
}
}
public class UserInformationElement implements InformationElement{
#Override
public <UserRepository> String getValue(UserRepository param) {
return *same code as in getUsersName(myDBRepository)*;
}
}
Here my generic type is not working: File is not reconize as java.io.File (same for my jpa repository) What am I doing wrong here ?
Is this the best practice for my needs ?
You've defined type parameters File and UserRepository that are shadowing the class names File and UserRepository. This is one of the surprises of naming type parameters the same as existing classes. The type parameters don't represent the classes, and they don't have bounds, so the compiler can only assume they have Object methods.
This is not the best practice. When implementing generic methods, the methods must remain generic and at least as wide-open with respect to bounds. To be able to restrict what the type parameter means later, define it on the class/interface, and let subclasses supply what it's supposed to mean for that specific implementation with a type argument.
The best solution here is to move InformationElement's type parameter to the class, and to supply type arguments in your subclasses. The methods are no longer generic, but they do use the type parameters defined on the interface/classes.
interface InformationElement<T> {
public String getValue (T param);
}
class NbFileLineInformationElement implements InformationElement<File>{
#Override
public String getValue(File param) {
return /*same code as in getLineNumber(myFile)*/;
}
}
class UserInformationElement implements InformationElement<UserRepository>{
#Override
public String getValue(UserRepository param) {
return /*same code as in getUsersName(myDBRepository)*/;
}
}
Say I've got two interfaces:
public interface IObjectOne<T>
{
List<T> digest(final List<T> myList);
}
public interface IObjectTwo<T>
{
List<T> create();
}
And an object which manages concrete implementations of these two interfaces, which must work over the same type.
public class Entity<T>
{
private IObjectOne<T> objectOne;
private IObjectTwo<T> objectTwo;
... setters
public IObjectOne<T> getObjectOne() {
return objectOne;
}
public IObjectTwo<T> getObjectTwo() {
return objectTwo;
}
}
These Entitys are stored in a Map, and I retrive one of them by a key:
final Entity<?> entity = entities.get(key);
Why cannot I do that?
entity.getObjectOne().digest(entity.getObjectTwo().create());
To do this, you need to do your operation in a method with a type variable:
<T> void doSomething(Entity<T> entity) {
entity.getObjectOne().digest(entity.getObjectTwo().create());
}
You can invoke this even for an Entity<?>, because that wildcard has some type, you just don't know it.
final Entity<?> entity = entities.get(key);
doSomething(entity);
Here:
final Entity<?> entity = entities.get(key);
you are saying: you absolutely do not care about the exact type of an entity. Reminder: wildcard means "I don't know" about the exact type.
And one consequence of using the wildcard for generics, as described here:
If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
In other words: by using the wildcard like this, the compiler is unable to correlate the generic types.
How are you creating the Map<String, Entity<YOUR_TYPE>>
You should parameterize your Entity<> since it is generic.
Map<String, Entity<YOUR_TYPE>> entities = new HashMap<>();
final Entity<YourType> entity = entities.get(key);
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 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
What I am trying to do is the following: Given a JSON document, map it to a POJO using Jackson, but define the type of the Generic class member based on a field in the JSON document.
My JSON looks as follows
{
"name": "Name",
"parameters": [
{"name": "paramName","value": "Value1", "#type": "string"},
{"name": "size","value": 5,"#type": "double"}
]
}
The class that maps to this JSON doc is
public class Strategy {
public String name;
public List<Parameter<?>> parameters;
}
Then I have a Generic class for this as follows
public class Parameter<T> {
public String name;
public T value;
#Override
public String toString() {
return this.getClass().getName();
}
}
So the idea is to tell Jackson when you deserialize the JSON document into the Strategy class and get to the parameters field, use the following classes as the Generic data type for the value member, i.e. I want to select it to be String or Double or Integer but I want that to be my decision so that it's generic and can be extended to any data type I want.
I realise I can use the annotation JsonTypeInfo which I added as well like this
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="#type")
But using these classes as is actually works but Jackson decides itself what the type should be based on its value and my size parameter is set to an Integer. If I set its value to 5.0 then its set to a Double which works, but what if I want one of the parameters to be a custom object?
The only way I could get this to work (and am not 100% happy with the solution) is to make the Parameter class abstract and then create concrete classes for each type that I want, i.e. ParameterString, ParameterDouble, ParameterCustomClass and then use the #JsonSubTypes annotations to set the correct class to use based on the type field in the JSON document.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="#type")
#JsonSubTypes({
#JsonSubTypes.Type(value=ParameterString.class, name="string"),
#JsonSubTypes.Type(value=ParameterDouble.class, name="double"),
#JsonSubTypes.Type(value=ParameterInstrument.class, name="instrument")
})
With the following class as an example
public class StrategyParameterString extends StrategyParameter<String> {
}
This isn't very extendable, I guess it will just need a new subtype annotation and concrete class added for every type that I need, but just doesn't feel as elegant as it could be.
Does anyone know of a better way of handling this ?
Thanks
Andrew
As I understand it, the types you want to represent in your Parameter list are reifiable, eg. String, Double, Instrument. You can take advantage of the fact that reifiable types have a runtime type token in the form of their class literal. This can be exploited to form the basis of a heterogenous type safe collection.
Instead of defining your Parameter class this way:
public class Parameter<T> {
public String name;
public T value;
:
:
}
}
You can define it as a concrete class that associates the object's value with its run time type token.
public class Parameter() {
private final Object m_value;
private final Class<?> m_cls;
private Parameter(Class<?> token, Object val) {
m_value = val;
m_cls = token;
}
public static <T> Parameter newInstance(Class<T> token, T value) {
return new Parameter(token, value);
}
:
:
public <T> T getValue(Class<T> token) {
if (token != m_cls) throw new ClassCastException("Type error");
return token.cast(m_value);
}
}
In this setting, type tokens and generic methods (rather than a generic type) are used to set and reestablish the type linkage for the desired value. The value you set can be any type and is guaranteed to be returned as the same type that you stored as long as the type tokens are consistent.
Note that constructors can not be generic. To address this, the constructor for Parameter has been made private and Parameter instances are formed by invoking the newInstance() static factory method (which can be generic).