creating a generic function to copy different objects - java

so i have a use case where i need to copy an object of classes ( classes may vary depending on the input type in factory.
here is a sample of what i am trying to do
public interface DataUtil {
// the main wrapper
static Object copyObject(Object payload){
if(payload instanceof Human))
return copyEntry((Human) payload);
if(payload instanceof Car))
return copyEntry((Car) payload);
if(payload instanceof Planet))
return copyEntry((Planet) payload);
return payload;
}
static Human copyEntry(Human human) {
return Human.builder()
.name(human.getName())
.age(human.getAge())
.build();
}
static Car copyEntry(Car car) {
return Car.builder()
.model(car.getModel())
.brand(car.getBrand())
.build();
}
static Planet copyEntry(Planet planet) {
// return builder like previous
}
}
If you look at copyObject function, it does the job as intended but he issue is in return type. At present, to make itself compatible, its returning an Object but i would rather prefer to return it specific class Object ( say Human or Car for instance )
Is there a way to get this done with Generics (using <T>)? or is this a bad approach in the first place to do?

Is there a way to get this done with Generics (using )? or is this
a bad approach in the first place to do?
It is a bad approach because you receive as parameter a Object.
You cannot infer from that the concrete type : whereas the instanceof you used. Which is not a fine approach.
Here two ideas (related enough)
1) Introducing a Copyable interface
You could introduce an interface that the classes of the objects you want to copy implement :
public interface Copyable<T> {
T copy(T t);
}
that could be implemented such as :
public class Human implements Copyable<Human> {
#Override
public Human copy(Human t) {
return Human.builder()
.name(human.getName())
.age(human.getAge())
.build();
}
}
So the general copy() method could look like :
// the main wrapper
static <T extends Copyable<T>> T copyObject(T payload) {
return payload.copy(payload);
}
And you could use it in this way :
Human human = new Human();
// set some fields ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile
2) Use the visitor pattern
As alternative, it is also a good case for the visitor pattern : you want to apply a processing according to the concrete type of the parameter.
It allows to group together copy operations as in your actual code.
The general copyObject() method could rely on CopyVisitor that will do the copy according to the concrete type of the parameter :
#SuppressWarnings("unchecked")
static <T extends Visited> T copyObject(T payload) {
CopyVisitor visitor = new CopyVisitor();
payload.accept(visitor);
return (T) visitor.getCopy();
}
Where CopyVisitor implements a classic Visitor interface :
public interface Visitor {
void visitHuman(Human human);
void visitCar(Car car);
void visitPlanet(Planet planet);
}
in this way :
public class CopyVisitor implements Visitor {
private Visited copy;
#Override
public void visitHuman(Human human) {
copy = Human.builder()
.name(human.getName())
.age(human.getAge())
.build();
}
#Override
public void visitCar(Car car) {
copy = Car.builder()
.model(car.getModel())
.brand(car.getBrand())
.build();
}
#Override
public void visitPlanet(Planet planet) {
//...
}
public Visited getCopy() {
return copy;
}
}
The visited classes (Car, Human, Plan) would implement a specific interface to "accept" the visitor :
public interface Visited {
void accept(Visitor visitor);
}
such as :
public class Human implements Visited {
#Override
public void accept(Visitor visitor) {
visitor.visitHuman(this);
}
}
So you can use the copy() method in this way :
Human human = new Human();
// set some fields ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile

Unfortunately you have to do some unchecked casts like this:
static <TPayload> TPayload copyObject(Object payload) {
if (payload instanceof Human)
return (TPayload) copyEntry((Human) payload);
if (payload instanceof Car)
return (TPayload) copyEntry((Car) payload);
if (payload instanceof Planet)
return (TPayload) copyEntry((Planet) payload);
return (TPayload) payload;
}
But as mentioned in the comments this does not prevent you from writing:
Number n = DataUtil.copyObject("someString");

If you have knowledge about the type in Object you can do it with:
static <T> T copyObject(Object payload)
{
if (payload instanceof Human)
{
return (T) copyEntry((Human) payload);
}
if (payload instanceof Car)
{
return (T) copyEntry((Car) payload);
}
if (payload instanceof Planet)
{
return (T) copyEntry((Planet) payload);
}
return (T) payload;
};
and then:
Human h1 = new ...
Human h2= copyObject(h1);
Even if Java's Type Erasure would not apply you need runtime knowledge for your language to do so aka "dependent typing".
So return type overloading found in some languages like in C++ wouldn't help for runtime type switches like in List<Object>.
But why you need this anyway, you will collect all object instances after the call in a new heterogeneous List again

Related

Effective version of writing the following method

Is there an elegant and best approach to write the following method?
private void throwException(Object obj) {
if (obj instanceof ClassA) {
ClassA resp = (ClassA) obj;
throw new CustomException(resp.getMessage(), resp.getCode());
} else if (obj instanceof ClassB) {
ClassB resp = (ClassB) obj;
throw new CustomException(resp.getMessage(), resp.getCode());
}
}
Note that ClassA and ClassB has the same exact properties. My point is that, I don't want to repeat the throw statement as much as possible.
Define a map like
Map<Class<?>, Function<Object, ? extends RuntimeException>> handlers = new LinkedHashMap<>();
The handlers will contain a Function that you can use to map the Object passed to throwException to get an exception. The key of the map is a class and value is the function that will map an object of the type (class) of the key to an exception.
Populate the above map as
handlers.put(ClassA.class, (obj) -> new CustomException(((ClassA) obj).getMessage(), ((ClassA) obj).getCode));
handlers.put(ClassB.class, (obj) -> new CustomException(((ClassB) obj).getMessage(), ((ClassB) obj).getCode));
With this, throwException would look like,
private void throwException(Object obj) {
Function<Object, ? extends RuntimeException> handler = handlers.entrySet().stream()
.filter(entry -> entry.getKey().isAssignableFrom(obj.getClass()))
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(() -> new RuntimeException("No handler found")); //Or use a default using orElseGet
throw handler.apply(obj);
}
I agree that it moves the casting elsewhere to make the method look clean.
The key part is the line
.filter(entry -> entry.getKey().isAssignableFrom(obj.getClass()))
We are checking if the object (passed to throwException) is of type returned by entry.getKey (the class of the map key). So, if you have inheritance hierarchy among the classes (ClassA, ClassB..), then you must populate the map in such an order so that the most generic ones (say like Object.class) comes after more specific ones.
A consequence of putting an entry into handlers with Object.class as the first entry would mean that the function (value) of Object.class will always be picked up for any object passed to it.
You can use Function<>s to wrap the getters into a custom interface beforehand.
interface Wrapper {
String getMessage();
int getCode();
<T> Function<T, Wrapper<T>> of(Function<T,String> getMsg, Function<T, Integer> getCde) {
return object -> new Wrapper() {
public String getMessage() { return getMsg.apply(object); }
public int getCode() { return getCde.apply(object); }
}
}
}
class Thrower {
Map<Class<?>, Supplier<Wrapper>> wrappers = new HashMap();
static {
wrappers.put(A.class, Wrapper.of(A.class, A::getMessage, A::getCode));
wrappers.put(B.class, Wrapper.of(B.class, B::getMessage, B::getCode));
}
void throwException(Object o) {
Wrapper wrapper = wrappers.get(o.getClass()).apply(o);
throw new CustomException(wrapper.getMessage(), wrapper.getCode());
}
}
You can kill two birds with one stone as this is a classical problem in the clean code design where you can choose to implement Visitor Design Pattern as a workaround to multiple If/else instanceof type of conditioning with a little bit of expansion to cover the problem of excessive throwing of new CustomExeption.
Here is what I can suggest you :
First it's better to change you design for ClassA and ClassB as:
abstract class ClassParent {
// your fields
public ClassParent (//your fields) {
// initializing your fields
}
public abstract void accept(ClassVisitor cv);
}
class ClassA extends ClassParent {
public ClassA(//your fileds) {
super(//your fileds);
}
/// other Implementation
public void accept(ClassVisitor cv) {
cv.visit(this);
}
}
class ClassB extends ClassParent {
public ClassB(//your fileds) {
super(//your fileds);
}
/// other Implementation
public void accept(ClassVisitor cv) {
cv.visit(this);
}
}
Now define your vistors as :
interface ClassVisitor {
abstract void visit(ClassA classA);
abstract void visit(ClassB classB);
}
class Visitor implements ClassVisitor {
public void visit(ClassA classA) {
classA.DoSomthing();
}
public void visit(ClassB classB) {
classB.DoSomthing();
}
}
Now it your ThrowException you can define :
private ClassVisitor visitor = new Visitor();
public void ThrowException(ClassParent classParent){
classParent.accept(visitor);
throw new CustomException(classParent.getMessage(), classParent.getCode);
}
This way you achieve both a cleaner code, more maintainable with
higher readablity by avoiding duplicate codes at the same time.

How to use instanceof with scala object?

I've the following scala hierarchy:
sealed trait SessionResult[+T] {
def toOption: Option[T]
}
object SessionResult {
trait SessionValue[T] extends SessionResult[T] {
def session: T
def toOption: Option[T] = Some(session)
}
trait NoSessionValue[T] extends SessionResult[T] {
def toOption: Option[T] = None
}
case class Decoded[T](session: T) extends SessionResult[T] with SessionValue[T]
case class CreatedFromToken[T](session: T) extends SessionResult[T] with SessionValue[T]
case object NoSession extends SessionResult[Nothing] with NoSessionValue[Nothing]
case object TokenNotFound extends SessionResult[Nothing] with NoSessionValue[Nothing]
case object Expired extends SessionResult[Nothing] with NoSessionValue[Nothing]
case class Corrupt(e: Exception) extends SessionResult[Nothing] with NoSessionValue[Nothing]
}
But I use this code from java and the following piece of code does not compile:
SessionResult<SomeSession> sr = ...
System.out.println(sr instanceof NoSession)
Why? And also how can I use instanceof to check the class of scala's object?
The error I'm getting is:
Inconvertible types; cannot cast SessionResult<SomeSession> to NoSession.
The problem lies in the fact that you're putting a hard bound on the generic parameter - NoSession is a SessionResult[Nothing].
So (in Java parlance) the only compatible variant of SessionResult<T> compatible to SessionResult.NoSession$ can be SessionResult<Nothing$>.
i.e. this will compile
public SessionResult<Nothing$> test() {
return null;
}
public void blah() {
if(test() instanceof SessionResult.NoSession$) {
}
}
while e.g. this won't
public <T> SessionResult<T> test() {
return null;
}
public void blah() {
if(test() instanceof SessionResult.NoSession$) {
}
}
Fortunately, since NoSession is an object, hence you can just reference-test the singleton value:
SessionResult.NoSession$.MODULE$.equals(test());
(equals is required as due to the variance you need upcast to Object - you can do that manually, but equals saves you some time on that)
Alternatively, you can just selectively wildcard the generic parameter, i.e.:
public static SessionResult<?> testYay() {
return SessionResult.NoSession$.MODULE$;
}
public static SessionResult<?> testNay1() {
return null;
}
public static SessionResult<?> testNay2() {
return SessionResult.Expired$.MODULE$;
}
public static <T> SessionResult<T> testNay3() {
return null;
}
public static void blah() {
//prints true
System.out.println(testYay() instanceof SessionResult.NoSession$);
//prints false
System.out.println(testNay1() instanceof SessionResult.NoSession$);
//prints false
System.out.println(testNay2() instanceof SessionResult.NoSession$);
//prints false (and compiles)
System.out.println((SessionResult<?>) testNay3() instanceof SessionResult.NoSession$);
}
This is a very hacky solution, but probably the most convenient for code that mostly deals with such equality checks in Java. As demonstrated in the testNay3, you can limit the "collateral damage" of using generic types this way via simple in-place casts.
EDIT: changed to wildcard as per Alexey's hint.

How does one restrict number of allowed types in Java generic type

Say, i have a generic type as below
public class GenericType<T> {
private T someVar;
public void setVar(T var) { this.someVar = var; }
//Rest of the code
}
I want to allow it to take only specific types(String/Integer/Double). I know about bounded wildcards but they don't help me here. In setVar(), I can check the instanceof and throw an Exception if type is not Integer/String etc. Is this the best way to do it?
I have the same problem when doing operations on this type. Depending on the type, I want to do different operations. Inheritance and bounded wildcards seem like the way to go in general for this kind of problem but these are primitive wrappers.
Using Inheritance:
Parent.java
public abstract class Parent<T> {
public abstract void display(T t);
}
ChildString.java
public class ChildString extends Parent<String> {
#Override
public void display(String t) {
// Do something here...
}
}
ChildInteger.java
public class ChildInteger extends Parent<Integer> {
#Override
public void display(Integer t) {
// Do something here...
}
}
ChildDouble.java
public class ChildDouble extends Parent<Double> {
#Override
public void display(Double t) {
// Do something here...
}
}
And access the class child rather than you directly access the parent class.
Update
Here another example:
GenericType.java
public class GenericType {
public void display(Object t) {
String msg;
if(t instanceof String) {
msg = "String";
} else if (t instanceof Integer) {
msg = "Integer";
} else if (t instanceof Double) {
msg = "Double";
} else {
msg = "Another Object";
}
System.out.println(msg);
}
}
SpecificGeneric.java
public class SpecificGeneric {
public static void main(String[] args) {
GenericType basicType = new GenericType();
basicType.display(new String());
basicType.display(new Integer(1));
basicType.display(new Double(0.1));
}
}
You cannot (more than extends something, but in your case you want few unrelated types, so it does not help).
What you can, is check instance passed to method (you already know it). If you want one instace of generic class for eg. String another for Integers, but don't allow eg. Point2D, you can make constructor with parameter Class clazz and check when constructing whether its allowed.
If you are more paranoid, you can store that clazz and in all function compare whether parameter is actualy that class.
This way, you can still create MyClass, but cannot create instance with this type. (But you can cast it, co its not fool proof)
Inferring the desired type say GenericType<Double> and using instanceof when neccesary is the quickest and easy option. Alternatively overload setVar(..) to accept the restricted types in your Generic class.
public static class GenericType<T>
{
private T someVar;
public void setVar(String var)
{
this.someVar = (T) var;
}
public void setVar(Integer var)
{
this.someVar = (T) var;
}
public void setVar(Double var)
{
this.someVar = (T) var;
}
}

Java generics (template) specialization possible (overriding template types with specific types)

I'm wondering what are the options to specialize generic types in Java, i.e. in a templated class to have specific overrides for certain types.
In my case I was a generic class (of type T) to return null usually, but return "" (the empty string), when T is the String type, or 0 (zero) when its the Integer type, etc.
Merely providing a type-specific overload of a method produces a "method is ambiguous" error:
e.g.:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Is the only option to subclass the generic class with a specific type (see StringBar in the following example?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
Is this is the only way, it's a bit of a pain to have to create a subclass for every type I want to specialize instead of an overload of get() in the Bar class.
I'm guessing I could check the instanceof in the Bar.get() method, e.g.
T get(T t) {
if (t instanceof String) return "";
if (t instanceof Integer) return 0;
else return null;
}
However I've been taught to avoid instanceof and use polymorphism when possible.
All things considered, the concensus appears to be that the StringBar method mentioned in the question is the only way to go.
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
Generics in Java are very different from templates in C++ in this respect. It is not possible to write a specific version of a generic class to do something different for a particular case, as C++ can do. It is also not possible to determine at run time what T is - this is because that information is not passed into the byte code (object code) and so doesn't even exist at runtime. This due to something called "type erasure".
BarString and BarInt would be the obvious way of doing this, but there are improvements you can make. For example you can write a generic Bar to cover the common cases, and then write specialized BarString and BarInt to implement special cases. Ensure that the instances can only be created through a factory, which takes the class of the object to be processed:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
That probably won't compile, but I don't have the time to work out the exact syntax. It does illustrate the principle.
The compiler is actually correct, because the following code is compile-time checked (Bar<String> barString = new Bar<String>();) when compiled, from
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
to
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
and is ambiguous as you can't have 2 identical methods with the same return types and the same parameter arguments.
See an explanation by Jon Skeet's:
What is the concept of erasure of generics in java?
Java Generics - Types erasures - when and what happens?
You can subclass Bar<T> and create StringBar (note I removed the static keyword) and override get() method.
public class BarString extends Bar<String> {
#Override
public String get(String x) {
return "";
}
}
Generics in Java aren't made for specialization. They're made for generalization! If you want to specialize for certain types, you should be specializing...through a subclass.
Often you don't need to do something in a specialized manner however. Your StringBar example is kind of contrived because you could have this:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
I don't see why you need to specialize for a String here.

Java: Instanceof and Generics

Before I look through my generic data structure for a value's index, I'd like to see if it is even an instance of the type this has been parametrized to.
But Eclipse complains when I do this:
#Override
public int indexOf(Object arg0) {
if (!(arg0 instanceof E)) {
return -1;
}
This is the error message:
Cannot perform instanceof check against type parameter E. Use instead its erasure Object since generic type information will be erased at runtime
What is the better way to do it?
The error message says it all. At runtime, the type is gone, there is no way to check for it.
You could catch it by making a factory for your object like this:
public static <T> MyObject<T> createMyObject(Class<T> type) {
return new MyObject<T>(type);
}
And then in the object's constructor store that type, so variable so that your method could look like this:
if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass())) {
return -1;
}
Two options for runtime type checking with generics:
Option 1 - Corrupt your constructor
Let's assume you are overriding indexOf(...), and you want to check the type just for performance, to save yourself iterating the entire collection.
Make a filthy constructor like this:
public MyCollection<T>(Class<T> t) {
this.t = t;
}
Then you can use isAssignableFrom to check the type.
public int indexOf(Object o) {
if (
o != null &&
!t.isAssignableFrom(o.getClass())
) return -1;
//...
Each time you instantiate your object you would have to repeat yourself:
new MyCollection<Apples>(Apples.class);
You might decide it isn't worth it. In the implementation of ArrayList.indexOf(...), they do not check that the type matches.
Option 2 - Let it fail
If you need to use an abstract method that requires your unknown type, then all you really want is for the compiler to stop crying about instanceof. If you have a method like this:
protected abstract void abstractMethod(T element);
You can use it like this:
public int indexOf(Object o) {
try {
abstractMethod((T) o);
} catch (ClassCastException e) {
//...
You are casting the object to T (your generic type), just to fool the compiler. Your cast does nothing at runtime, but you will still get a ClassCastException when you try to pass the wrong type of object into your abstract method.
NOTE 1: If you are doing additional unchecked casts in your abstract method, your ClassCastExceptions will get caught here. That could be good or bad, so think it through.
NOTE 2: You get a free null check when you use instanceof. Since you can't use it, you may need to check for null with your bare hands.
Old post, but a simple way to do generic instanceOf checking.
public static <T> boolean isInstanceOf(Class<T> clazz, Class<T> targetClass) {
return clazz.isInstance(targetClass);
}
Provided your class extends a class with a generic parameter, you can also get this at runtime via reflection, and then use that for comparison, i.e.
class YourClass extends SomeOtherClass<String>
{
private Class<?> clazz;
public Class<?> getParameterizedClass()
{
if(clazz == null)
{
ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
clazz = (Class<?>)pt.getActualTypeArguments()[0];
}
return clazz;
}
}
In the case above, at runtime you will get String.class from getParameterizedClass(), and it caches so you don't get any reflection overhead upon multiple checks. Note that you can get the other parameterized types by index from the ParameterizedType.getActualTypeArguments() method.
I had the same problem and here is my solution (very humble, #george: this time compiling AND working ...).
My probem was inside an abstract class that implements Observer.
The Observable fires method update(...) with Object class that can be any kind of Object.
I only want to handler Objects of type T
The solution is to pass the class to the constructor in order to be able to compare types at runtime.
public abstract class AbstractOne<T> implements Observer {
private Class<T> tClass;
public AbstractOne(Class<T> clazz) {
tClass = clazz;
}
#Override
public void update(Observable o, Object arg) {
if (tClass.isInstance(arg)) {
// Here I am, arg has the type T
foo((T) arg);
}
}
public abstract foo(T t);
}
For the implementation we just have to pass the Class to the constructor
public class OneImpl extends AbstractOne<Rule> {
public OneImpl() {
super(Rule.class);
}
#Override
public void foo(Rule t){
}
}
Or you could catch a failed attempt to cast into E eg.
public int indexOf(Object arg0){
try{
E test=(E)arg0;
return doStuff(test);
}catch(ClassCastException e){
return -1;
}
}
Technically you shouldn't have to, that's the point of generics, so you can do compile-type checking:
public int indexOf(E arg0) {
...
}
but then the #Override may be a problem if you have a class hierarchy. Otherwise see Yishai's answer.
The runtime type of the object is a relatively arbitrary condition to filter on. I suggest keeping such muckiness away from your collection. This is simply achieved by having your collection delegate to a filter passed in a construction.
public interface FilterObject {
boolean isAllowed(Object obj);
}
public class FilterOptimizedList<E> implements List<E> {
private final FilterObject filter;
...
public FilterOptimizedList(FilterObject filter) {
if (filter == null) {
throw NullPointerException();
}
this.filter = filter;
}
...
public int indexOf(Object obj) {
if (!filter.isAllows(obj)) {
return -1;
}
...
}
...
}
final List<String> longStrs = new FilterOptimizedList<String>(
new FilterObject() { public boolean isAllowed(Object obj) {
if (obj == null) {
return true;
} else if (obj instanceof String) {
String str = (String)str;
return str.length() > = 4;
} else {
return false;
}
}}
);
Let Java determine it and catch the exception bottom line.
public class Behaviour<T> {
public void behave(Object object) {
T typedObject = null;
try { typedObject = (T) object; }
catch (ClassCastException ignored) {}
if (null != typedObject) {
// Do something type-safe with typedObject
}
}
}

Categories