How to protect private field in class with getter in java - java

I have the following code.
public class GetterTest {
public static void main(String[] args) {
Car car = new Car();
StringBuilder wheel = car.getWheel();
wheel.append("asd");
System.out.println(car.getWheel());
}
}
class Car {
private StringBuilder wheel;
public Car() {
wheel = new StringBuilder("a");
}
public StringBuilder getWheel() {
return wheel;
}
public void setWheel(StringBuilder wheel) {
this.wheel = wheel;
}
}
The problem here is even I have a getter it don't protect the variable and it is changed after using it. How to protect the variable better?

You shouldn't return the StringBuilder but rather the value. This creates a new String which isn't connected to your backing StringBuilder anymore.
public String getWheel() {
return wheel.toString();
}
However if you really want to return a StringBuilder, you can create a new one with the current one's data, essentially disconnecting both instances:
public StringBuilder getWheel() {
return new StringBuilder(wheel.toString());
}

A StringBuilder variable is not a good candidate for a getter. It would make more sense to have a getter that returns the current String value of that StringBuilder, since a String it immutable :
public String getWheel() {
return wheel.toString();
}
The setter should also be changed, since the current impl allows the caller of the setter to mutate the StringBuilder that was passed to the setter, and thus mutate the member after the setter is called.
public void setWheel (String wheel)
{
this.wheel = new StringBuilder (wheel);
}

In the field's that you want to protect getter you can clone the field instead of returning the current field.
public void doSomething() {
Car car = new Car();
Wheel wheel = car.getWheel();
wheel.getaVariable().append("asd");
System.out.println(car.getWheel());
}
public class Car {
private Wheel wheel;
public Car() {
wheel = new Wheel();
}
public Wheel getWheel() {
Wheel output = null;
try {
output = wheel.clone();
} catch (CloneNotSupportedException e) {
// Manage exception
}
return output;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
}
public class Wheel implements Cloneable {
private StringBuilder aVariable;
public Wheel() {
aVariable = new StringBuilder("a");
}
public StringBuilder getaVariable() {
return aVariable;
}
public void setaVariable(StringBuilder aVariable) {
this.aVariable = aVariable;
}
#Override
protected Wheel clone() throws CloneNotSupportedException {
Wheel clone = (Wheel) super.clone();
clone.setaVariable(new StringBuilder(aVariable));
return clone;
}
#Override
public String toString() {
return aVariable.toString();
}
}

Related

Question on diamond operator for design pattern strategy

Small question regarding the diamond operator and design pattern strategy for Java, please.
I would like to implement a very specific requirement:
there are some objects to store (in my example called MyThingToStore)
and the requirement is to store them with different kinds of data structures, for comparison.
Therefore, I went to try with a strategy pattern, where each of the strategies is a different way to store, I think this pattern is quite lovely.
The code is as follows:
public class MyThingToStore {
private final String name;
public MyThingToStore(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyThingToStore that = (MyThingToStore) o;
return Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(name);
}
#Override
public String toString() {
return "MyThingToStore{" +
"name='" + name + '\'' +
'}';
}
}
public class MyStorage {
private final StorageStrategy storageStrategy;
public MyStorage(StorageStrategy storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
public interface StorageStrategy {
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy{
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And this is working fine, very happy, especially tackled the requirement "easy to change the data structure to do the actual store".
(By the way, side question, if there is an even better way to do this, please let me know!)
Now, looking online at different implementations of strategy patterns, I see this diamond operator which I am having a hard time understanding:
MyThingToStore stays the same.
public class MyStorage {
private final StorageStrategy<MyThingToStore> storageStrategy; //note the diamond here
public MyStorage(StorageStrategy<MyThingToStore> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(MyThingToStore myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
#Override
public String toString() {
return "MyStorage{" +
"storageStrategy=" + storageStrategy +
'}';
}
}
public interface StorageStrategy<MyThingToStore> {
//note the diamond, and it will be colored differently in IDEs
void addToStore(MyThingToStore myThingToStore);
int getSize();
}
public class StorageUsingArrayListStrategy implements StorageStrategy<MyThingToStore> {
private final List<MyThingToStore> storeUsingArrayList = new ArrayList<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingArrayList.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingArrayList.size();
}
}
public class StorageUsingHashSetStrategy implements StorageStrategy<MyThingToStore> {
private final Set<MyThingToStore> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(MyThingToStore myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
public class Main {
public static void main(String[] args) {
final StorageStrategy<MyThingToStore> storageStrategy = new StorageUsingArrayListStrategy();
final MyStorage myStorage = new MyStorage(storageStrategy);
myStorage.addToStore(new MyThingToStore("firstItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
myStorage.addToStore(new MyThingToStore("duplicatedSecondItem"));
System.out.println(myStorage.getSize()); //changing strategy will return a different size, working!
}
}
And both versions will yield the same good result, also be able to answer requirements.
My question is: what are the differences between the version without a diamond operator, and the version with the diamond operator, please?
Which of the two ways are "better" and why?
While this question might appear to be "too vague", I believe there is a reason for a better choice.
I think the confusion comes from how you named type parameter for StorageStrategy in your 2nd example.
Let's name it T for type instead. T in this case is just a placeholder to express what type of objects your StorageStrategy can work with.
public interface StorageStrategy<T> {
void addToStore(T myThingToStore);
int getSize();
}
E.g.
StorageStrategy<MyThingToStore> strategy1 = // Initialization
StorageStrategy<String> strategy2 = // Initialization
strategy1.addToStore(new MyThingToStore("Apple"));
// This works fine, because strategy2 accepts "String" instead of "MyThingToStore"
strategy2.addToStore("Apple");
// Last line doesn't work, because strategy1 can only handle objects of type "MyThingToStore"
strategy1.addToStore("Apple");
To make it work properly, you need to change your different StorageStrategy implementations to also include the type parameter.
public class StorageUsingHashSetStrategy<T> implements StorageStrategy<T> {
private final Set<T> storeUsingHashSet = new HashSet<>();
#Override
public void addToStore(T myThingToStore) {
storeUsingHashSet.add(myThingToStore);
}
#Override
public int getSize() {
return storeUsingHashSet.size();
}
}
And lastly you also want to have a type paremeter for MyStorage
public class MyStorage<T> {
private final StorageStrategy<T> storageStrategy;
public MyStorage(StorageStrategy<T> storageStrategy) {
this.storageStrategy = storageStrategy;
}
public void addToStore(T myThingToStore) {
storageStrategy.addToStore(myThingToStore);
}
public int getSize() {
return storageStrategy.getSize();
}
}
Now you can create a MyStorage and can use it to store essentially any object into it and not just MyThingToStore. Whether that is something you want or not is up to you.
In the second code sample in the declaration of the interface StorageStrategy<MyThingToStore>, MyThingToStore is a Type Variable.
I.e. it's not the actual type, only a placeholder for a type, like T. The common convention is to use single-letter generic type variables (T, U, R, etc.), otherwise it might look confusing like in this case.
Note that in the class declarations, like:
public class StorageUsingArrayListStrategy
implements StorageStrategy<MyThingToStore>
MyThingToStore is no longer a type variable, but the name of the class MyThingToStore because in this case parameterized interface is implemented by a non-parameterized class (i.e. the actual type known to the compile is expected to be provided).

Choosing between extended classes inside constructor

I am writing a java (processing) library for unexperienced students, and am looking for the best architecture for implementing it.
Initialization of an object should be as close as possible to this:
myObject = new General("type1");
Such that myObject will become an instance of Type1 which extends General:
class General {
public General() {}
}
class Type1 extends General {
public Type1() {}
}
class Type2 extends General {
public Type1() {}
}
As far as I know, this isn't possible (choosing between extended classes during initialization), but I'm looking for the closest solution possible.
So far, my best solution is to make a static initializer inside General:
class General {
...
static General init (String type) {
General temp;
if (type.equals("type1") {
temp = new Type1();
}
...
return temp;
}
and the initialization is:
General myObject;
myObject = General.init("type1");
This is far from ideal...
thanks.
you can make a factory class that manages initialization.
instead of doing it inside the parent.
// Empty vocabulary of actual object
public interface IPerson
{
string GetName();
}
public class Villager : IPerson
{
public string GetName()
{
return "Village Person";
}
}
public class CityPerson : IPerson
{
public string GetName()
{
return "City Person";
}
}
public enum PersonType
{
Rural,
Urban
}
/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
public IPerson GetPerson(PersonType type)
{
switch (type)
{
case PersonType.Rural:
return new Villager();
case PersonType.Urban:
return new CityPerson();
default:
throw new NotSupportedException();
}
}
}
The State design pattern can be a solution here. Rather than the constructor argument changing the type of the object (which isn't possible) it can set a field of the object, to make it behave as if its type is different.
package stackoverflow.questions;
public class Main {
private interface MyInterface {
String foo();
int bar();
}
private static class Type1 implements MyInterface {
#Override public String foo() { return "lorem ipsum "; }
#Override public int bar() { return 6; }
}
private static class Type2 implements MyInterface {
#Override public String foo() { return "dolor sit amet"; }
#Override public int bar() { return 7; }
}
public static class General {
private final MyInterface type;
public General(String type) {
try {
this.type = (MyInterface) Class
.forName("stackoverflow.questions.Main$" + type)
.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("Invalid type: " + type);
}
}
public String method1() { return type.foo(); }
public int method2() { return type.bar(); }
}
public static void main(String... args) {
General one = new General("Type1");
General two = new General("Type2");
System.out.println(one.method1() + two.method1());
System.out.println(one.method2() * two.method2());
}
}

How to pass down the new operator in a method

For example, if I wanted to do something like this to call a method:
myLights.addLight(new Fluorescent(lumens));
in order to create a new object in the Fluorescent class and pass down the lumens data. How would I then set up the method to receive this?
Assuming method is not returning anything.
void addlight(Fluorescent a){
// your logic
}
In your Lights class create a method that accepts a Fluorescent object as an argument.
public void addLight(Fluorescent fluorescent){
// do something
}
Here is a basic example:
public class HelloWorld
{
public static void main(String[] args)
{
Light light = new Light();
light.addLight(new Fluorescent("300 lm"));
System.out.print(light.getLumen());
}
}
public class Light {
private String lumen;
public Light() {
}
public void setLumens(String lumen){
this.lumen = lumen;
}
public String getLumen(){
return this.lumen;
}
public void addLight(Fluorescent fluorescent) {
if(fluorescent.getLumen() != null) {
this.lumen = fluorescent.getLumen();
}
}
}
public class Fluorescent {
private String lumen;
public Fluorescent(String lumen){
this.lumen = lumen;
}
public void setLumen(String lumen){
this.lumen = lumen;
}
public String getLumen(){
return this.lumen;
}
}
Seeing that a Fluorescent is a Light, you might want to look in to inheritance.
Look here for some explanation
Java 101: Inheritance in Java, Part 1
public class Fluorescent() {
public Fluorescent(String lumens) {
// do something
}
}
public class Lights() {
public void addLight(Fluorescent fluorescent) {
// do something
}
}

How to set Immutablity to the class when reference of mutable class is present

public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 = "+imc1);
mc.setId(2);
ImClass imc2 = new ImClass(mc);
System.out.println("imc2 = "+imc2);
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = mClass;
}
public MClass getmClass() {
return mClass;
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I want to provide complete immutablity to the class IMClass, As we can see IMclass is immutable but it has an instance variable mclass that is the reference of MClass and MClass is a mutable class.
I have tried changing the getter method getmClass() as below
public MClass getmClass() {
return (MClass) mClass.clone();
}
but it is not allowing me to do so, Could some one please correct it that where i am getting wrong.
Thanks in advance
I have tried this but still getting the same result, values are getting updated
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 = "+imc1);
mc.setId(2);
ImClass imc2 = new ImClass(mc);
System.out.println("imc2 = "+imc2);
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
public MClass getmClass() {
return (MClass)mClass.clone();
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass implements Cloneable{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
There are a lot of good ideas floating around. Here is how I would summarize it:
Avoid using clone if possible, and favor using a copy-constructor instead. See Joshua Bloch's thoughts on this matter.
To ensure immutability, you need to make sure you copy the MClass instance that is passed to the ImClass constructor. Otherwise, whoever originally passed the MClass instance can still make changes to it.
Consider creating an immutable wrapper around the MClass class, perhaps by using inheritance.
This is one way that this can be achieved. There are certainly other ways:
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 before = " + imc1);
mc.setId(2);
System.out.println("imc1 after = " + imc1); // continues printing 1.
imc1.getmClass().setId(3); // changes not allowed on the immutable copy, throws exception.
}
}
public final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (mClass == null ? null : mClass.createImmutableCopy());
}
public MClass getmClass() {
return mClass;
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
public class MClass {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public MClass createImmutableCopy() {
return new ImmutableMClass(this);
}
private static class ImmutableMClass extends MClass {
public ImmutableMClass(MClass src) {
super.setId(src.getId());
}
#Override
public void setId(int id) {
throw new UnsupportedOperationException("immutable instance.");
}
}
}
EDIT: How to make the clone method work
If you still want to do it the cloning way, make sure you follow these 2 steps:
Expose the clone as a public method (as already suggested), but, ideally, without swallowing the exception so that you don't get an inexplicable NullPointerException if something doesn't work. Although, technically, the CloneNotSupportedException exception should never happen if you don't forget step #2.
Like this:
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
Make sure that the MClass implements the Cloneable interface.
Like this:
public class MClass implements Cloneable {
// ...
}
But again, to make sure that the private MClass instance within the ImClass is "immutable", you'll need to call clone in 2 places:
In the ImClass.getmClass() method, as you are already doing.
Also in the ImClass constructor. If you forget this one, then it is still possible to modify it, so immutability hasn't been achieved fully.
Like this:
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
EDIT 2: About why it appears that your code is still not working
The code should be working now, but if I look at your current main method, you are not testing immutability correctly. You are checking the values from 2 different instances of ImClass.
The following is a more valid test:
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc = new ImClass(mc);
System.out.println("imc = " + imc); // should print 1
mc.setId(2);
System.out.println("imc = " + imc); // should still print 1 if immutability works
imc.getmClass().setId(3);
System.out.println("imc = " + imc); // should still print 1 if immutability works
}
If you are trying to achieve some kind of immutable wrapper around an a mutable class, perhaps better idea would be extending it and overriding all the places where it is mutated.
class IMWrapper extends MClass {
public IMWrapper(int id) {
super.setId(id);
}
#Override
void setId(int id) {
throw new UnsupportedOperationException("you can't modify this instance");
}
...
}
Defensive copying is a good idea, you should just implement copy constructor for MClass:
class MClass {
// ...
public MClass(MClass copied) {
this.id = copied.id;
}
}
You already narrowed down the problem to copying/cloning an object.
You can find the solution here: How do I copy an object in Java?
The problem is that the clone() method of MClass is not visible in ImClass.
It will work when you add the following method to MClass:
#Override
public Object clone() {
try {
return super.clone();
} catch (Exception e) {
return null;
}
}
And change your constructor to clone the object there as well (as by Jon Skeet's comment):
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
My working code
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc = new ImClass(mc);
System.out.println("imc = " + imc); // should print 1
mc.setId(2);
System.out.println("imc = " + imc); // should still print 1 if immutability works
imc.getmClass().setId(3);
System.out.println("imc = " + imc); // should still print 1 if immutability works
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
public MClass getmClass() {
return (MClass)mClass.clone();
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass implements Cloneable{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}

How to 'wrap' two classes with identical methods?

I have to handle two classes with identical methods but they don't implement the same interface, nor do they extend the same superclass. I'm not able / not allowed to change this classes and I don't construct instances of this classes I only get objects of this.
What is the best way to avoid lots of code duplication?
One of the class:
package faa;
public class SomethingA {
private String valueOne = null;
private String valueTwo = null;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
And the other...
package foo;
public class SomethingB {
private String valueOne;
private String valueTwo;
public String getValueOne() { return valueOne; }
public void setValueOne(String valueOne) { this.valueOne = valueOne; }
public String getValueTwo() { return valueTwo; }
public void setValueTwo(String valueTwo) { this.valueTwo = valueTwo; }
}
(In reality these classes are larger)
My only idea is now to create a wrapper class in this was:
public class SomethingWrapper {
private SomethingA someA;
private SomethingB someB;
public SomethingWrapper(SomethingA someA) {
//null check..
this.someA = someA;
}
public SomethingWrapper(SomethingB someB) {
//null check..
this.someB = someB;
}
public String getValueOne() {
if (this.someA != null) {
return this.someA.getValueOne();
} else {
return this.someB.getValueOne();
}
}
public void setValueOne(String valueOne) {
if (this.someA != null) {
this.someA.setValueOne(valueOne);
} else {
this.someB.setValueOne(valueOne);
}
}
public String getValueTwo() {
if (this.someA != null) {
return this.someA.getValueTwo();
} else {
return this.someB.getValueTwo();
}
}
public void setValueTwo(String valueTwo) {
if (this.someA != null) {
this.someA.setValueTwo(valueTwo);
} else {
this.someB.setValueTwo(valueTwo);
}
}
}
But I'm not realy satisfied with this solution. Is there any better / more elegant way to solve this problem?
A better solution would be to create an interface to represent the unified interface to both classes, then to write two classes implementing the interface, one that wraps an A, and another that wraps a B:
public interface SomethingWrapper {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
};
public class SomethingAWrapper implements SomethingWrapper {
private SomethingA someA;
public SomethingWrapper(SomethingA someA) {
this.someA = someA;
}
public String getValueOne() {
return this.someA.getValueOne();
}
public void setValueOne(String valueOne) {
this.someA.setValueOne(valueOne);
}
public String getValueTwo() {
return this.someA.getValueTwo();
}
public void setValueTwo(String valueTwo) {
this.someA.setValueTwo(valueTwo);
}
};
and then another class just like it for SomethingBWrapper.
There, a duck-typed solution. This will accept any object with valueOne, valueTwo properties and is trivially extensible to further props.
public class Wrapper
{
private final Object wrapped;
private final Map<String, Method> methods = new HashMap<String, Method>();
public Wrapper(Object w) {
wrapped = w;
try {
final Class<?> c = w.getClass();
for (String propName : new String[] { "ValueOne", "ValueTwo" }) {
final String getter = "get" + propName, setter = "set" + propName;
methods.put(getter, c.getMethod(getter));
methods.put(setter, c.getMethod(setter, String.class));
}
} catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueOne() {
try { return (String)methods.get("getValueOne").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueOne(String v) {
try { methods.get("setValueOne").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
public String getValueTwo() {
try { return (String)methods.get("getValueTwo").invoke(wrapped); }
catch (Exception e) { throw new RuntimeException(e); }
}
public void setValueTwo(String v) {
try { methods.get("setValueTwo").invoke(wrapped, v); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
You can use a dynamic proxy to create a "bridge" between an interface you define and the classes that conform but do not implement your interface.
It all starts with an interface:
interface Something {
public String getValueOne();
public void setValueOne(String valueOne);
public String getValueTwo();
public void setValueTwo(String valueTwo);
}
Now you need an InvocationHandler, that will just forward calls to the method that matches the interface method called:
class ForwardInvocationHandler implements InvocationHandler {
private final Object wrapped;
public ForwardInvocationHandler(Object wrapped) {
this.wrapped = wrapped;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes());
return match.invoke(wrapped, args);
}
}
Then you can create your proxy (put it in a factory for easier usage):
SomethingA a = new SomethingA();
a.setValueOne("Um");
Something s = (Something)Proxy.newProxyInstance(
Something.class.getClassLoader(),
new Class[] { Something.class },
new ForwardInvocationHandler(a));
System.out.println(s.getValueOne()); // prints: Um
Another option is simpler but requires you to subclass each class and implement the created interface, simply like this:
class SomethingAImpl extends SomethingA implements Something {}
class SomethingBImpl extends SomethingB implements Something {}
(Note: you also need to create any non-default constructors)
Now use the subclasses instead of the superclasses, and refer to them through the interface:
Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl
o.setValueOne("Uno");
System.out.println(o.getValueOne()); // prints: Uno
i think your original wrapper class is the most viable option...however it can be done using reflection, your real problem is that the application is a mess...and reflection is might not be the method you are looking for
i've another proposal, which might be help: create a wrapper class which has specific functions for every type of classes...it mostly copypaste, but it forces you to use the typed thing as a parameter
class X{
public int asd() {return 0;}
}
class Y{
public int asd() {return 1;}
}
class H{
public int asd(X a){
return a.asd();
}
public int asd(Y a){
return a.asd();
}
}
usage:
System.out.println("asd"+h.asd(x));
System.out.println("asd"+h.asd(y));
i would like to note that an interface can be implemented by the ancestor too, if you are creating these classes - but just can't modify it's source, then you can still overload them from outside:
public interface II{
public int asd();
}
class XI extends X implements II{
}
class YI extends Y implements II{
}
usage:
II a=new XI();
System.out.println("asd"+a.asd());
You probably can exploit a facade along with the reflection - In my opinion it streamlines the way you access the legacy and is scalable too !
class facade{
public static getSomething(Object AorB){
Class c = AorB.getClass();
Method m = c.getMethod("getValueOne");
m.invoke(AorB);
}
...
}
I wrote a class to encapsulate the logging framework API's. Unfortunately, it's too long to put in this box.
The program is part of the project at http://www.github.com/bradleyross/tutorials with the documentation at http://bradleyross.github.io/tutorials. The code for the class bradleyross.library.helpers.ExceptionHelper in the module tutorials-common is at https://github.com/BradleyRoss/tutorials/blob/master/tutorials-common/src/main/java/bradleyross/library/helpers/ExceptionHelper.java.
The idea is that I can have the additional code that I want to make the exception statements more useful and I won't have to repeat them for each logging framework. The wrapper isn't where you eliminate code duplication. The elimination of code duplication is in not having to write multiple versions of the code that calls the wrapper and the underlying classes. See https://bradleyaross.wordpress.com/2016/05/05/java-logging-frameworks/
The class bradleyross.helpers.GenericPrinter is another wrapper that enables you to write code that works with both the PrintStream, PrintWriter, and StringWriter classes and interfaces.

Categories

Resources