public void test(Object obj){
//Here i have to set the values of the obj using its setter .
}
Test can be invoked with two objects as parameter. EG: test(standalone) and test(webapp), where standalone and webapp are beans.
public class standalone{
int version;
//setter and getter
}
public class Webapp{
String version;
//setter and getter
}
This test method has to set the values accordin to the parameter object.
Eg: IF i pass standalone as param. standalone's setter method shd be called. How to achieve this?
Note : Without using interface. How to do this?
Thanks.
public static void setVersion(Object obj, int v) throws Exception {
for (Method m : obj.getClass().getMethods()) {
final Class<?>[] t = m.getParameterTypes();
if (m.getName().equals("setVersion") && t.length == 1)
m.invoke(obj, t[0] == String.class? String.valueOf(v) : v);
break;
}
}
You could make both StandAlone and WebApp implement an interface, eg
interface VersionSettable {
void setVersion(int version);
}
public class Standalone implements VersionSettable{
int version;
//setter and getter
}
public class Webapp implements VersionSettable{
int version;
//setter and getter
}
public void test(VersionSettable versionSettable){
versionSettable.setVersion(42);
}
In the simpliest way you could do like this:
public void test(Object obj) {
if( obj instanceof Standalone ) {
((Standalone)obj).setVersion(1);
} else if (obj instanceof WebApp ) {
((WebApp)obj).setVersion(1);
}
}
Try to avoid use of reflection to achieve this because it will make refactoring tasks really hard. The same would be applied to compare the class name with a string.
If you want something more elegant you could do something like this:
public class abstract AbstractEnv {
int version = 0;
// setters and getters
}
public class Standalone extends AbstractEnv{
}
public class Webapp extends AbstractEnv{
}
with this approach you can configure it like this:
public void test(AbstractEnv obj) {
obj.setVersion(1);
}
Both of your classes should implement an interface like VersionSettable. Which declares the method setVersion(int version).
public class standalone implements VersionSettable {
int version;
//setter and getter
}
public class Webapp implements VersionSettable {
int version;
//setter and getter
}
interface VersionSettable {
setVersion(int version);
}
Then you can change your test method to this:
public void test(VersionSettable obj){
obj.setVersion(17);
}
I think would be best if you use inheritance in this case, because (as far as I can get it)
both Standalone and WebApp are Applications.
So you can define a top class "Application" and both StandaloneApp and WebApp extend it, because an "is a" relationship could be defined.
Skeleton code:
define class Application
define class StandaloneApp extends Application, implements method setVersion(int)
define class WebApp extends Application, implements method setVersion(int)
define test method, which accepts "Application" obj in the arguments
Also you can apply any of the interface solutions, presented above.
You can simply do this:
interface SetVersion{
void setVersion(int version);
}
class Standalone implements SetVersion{}
class WebApp implements SetVersion{}
public void test(SetVersion version){
version.setVersion(1);
}
Or the simplest way would be to use .instanceOf
if(obj.instanceOf(Standalone)){
}
Related
Is there a way to store "extended enum" with JPA ?
I'm working with abstract object in my spring boot project and my base object can have multiple states. The object extending it can have the base state but also other specific states. You can't extend enum in Java, so my I first tought of using an interface with a default method isCommon to discriminate between my common enum values and my extended enum values in my services.
However I can't use the annotation #Enumerated on my property anymore. Is there a way to make it work or another pattern I could use ?
A small code sample to provide some context :
#Entity
abstract class AbstractFoo {
public StateInterface state;
}
#Entity
class ConcreteFoo extends AbstractFoo {
}
#Service
class ConcreteFooService {
public boolean isCommonState(ConcreteFoo foo) {
return foo.state.isCommon();
}
}
interface StateInterface {
default boolean isCommon() {
return false;
}
}
enum CommonState extends StateInterface {
BEGIN, END;
#Override
boolean isCommon() {
return true;
}
}
enum SpecificState extends StateInterface {
MIDDLE;
}
I would suggest you using the following Enum instead:
enum State {
BEGIN(true), MIDDLE(false), END(true);
private final boolean common;
State(boolean common) {
this.common = common;
}
public boolean isCommon() {
return common;
}
}
For your use case, this is the best I can think of.
I'm using spring and cglib and i have those classes:
public class A {
.
.
private Souscripteur souscripteur;
private List<B> contrat;
// getter and setter
}
public class B {
.
.
private Souscripteur souscripteur;
//getter and setter
}
and the Class A and B have the same souscripteur, so when i load the Class A and try to load the class B, i get the Souscripteur of the class B EnhancerByCGLIB.
For that, when i try to do this :
if(b.getSouscriteur() instanceof PersonnePhysique) {
//do something
} else {
//do nothing
}
when i inspect the code, the object enhanced is a PersonnePhysique, but if(b.getSouscriteur() instanceof PersonnePhysique) return false
My class PersonnePhysique is like this :
public class PersonnePhysique extends Souscriteur {
//
}
Hibernate generates proxies based on the declared, expected type (Souscripteur), so you'll get a lazy-loaded proxy extending Souscripteur - hence, no PersonnePhysique in the instanceof sense.
You have to avoid testing concrete types here, and rather call polymorphic methods on your entities (which is, by the way, more object-oriented).
Your use case, provided you are calling a method doSomething(), would become:
b.getSouscriteur().doSomething()
with the following implementations:
public class Souscripteur {
public void doSomething() {
// do nothing
}
}
public class PersonnePhysique extends Souscripteur {
#Override
public void doSomething() {
// do something here
}
}
I have several legacy classes that have no common interface nor superclass, though have the same methods. Most of these methods are protected.
Anyhow, I'd like to write a service that executes always the same routine on these classes, and thus call always the same methods, no matter what class it is.
Normally I'd give these classes a common interface, but I cannot modify the legacy classes, though I have to work with them.
Is there any chance to group them? Maybe a designpattern I'm not aware of?
class classA {
protected String getData() {
return "I'm class A";
}
}
class classB {
protected String getData() {
return "I'm class B";
}
}
class MyGeneralService {
void execute(<ClassA or B> clazz) {
//do something
clazz.getData();
//do something
//call another methods that are common to both classes
}
}
This sounds like exactly the kind of problem the Adapter Pattern is designed to solve.
Essentially, wrap each of your legacy classes with an associated adapter class, which does implement a common interface. The adapter class should simply forward method calls as appropriate.
Note: The fact that the methods you want to call from the outside world are protected is curious. The adapter pattern will not help you call methods you were previously unable to call (other than via reflection, of course).
I suggest to use decorator pattern. If You create decorator class using the same name of package then You will have access to protected method
If the object can only be class A or B, then why not:
if (clazz instanceof A) {
((A)clazz).getData();
} else {
((B)clazz).getData();
}
Or create wrappers for A and B that implement a common interface as asuggested ijn the comments.
Otherwise you could use reflection:
void execute(Object obj) {
//do something
try {
Method method = obj.getClass().getMethod("getData");
method.setAccessible(true);
String value = (String) method.invoke(obj);
//do something
//call another methods that are common to both classes
} catch (NoSuchMethodException nsmx) {
// object does not have the method
}
}
Something like this should work:
class ClassA {
protected String getData() {
return "I'm class A";
}
}
class ClassB {
protected String getData() {
return "I'm class B";
}
}
class ClassC {
public String getData() {
return "I'm class C";
}
}
interface HasData {
public String getData();
}
class DataA extends ClassA implements HasData {
#Override
public String getData() {
return super.getData();
}
}
class DataB extends ClassB implements HasData {
#Override
public String getData() {
return super.getData();
}
}
class DataC extends ClassC implements HasData {
// No need to redefine it if it is already public.
}
class MyGeneralService {
public <C extends HasData> void execute(C c) {
c.getData();
}
}
I wanted to implement a method in a abstract class that is called by the inherited classes and uses their values.
For instance:
abstract class MyClass{
String value = "myClass";
void foo(){System.out.println(this.value);}
}
public class childClass{
String value="childClass";
void foo(){super.foo();}
}
public static void main(String[] args){
new childClass.foo();
}
This will output "myClass" but what I really want is to output "childClass". This is so I can implement a "general" method in a class that when extended by other classes it will use the values from those classes.
I could pass the values as function arguments but I wanted to know if it would be possible to implement the "architecture" I've described.
A super method called by the inherited class which uses the values from the caller not itself, this without passing the values by arguments.
You could do something like this:
abstract class MyClass {
protected String myValue() {
return "MyClass";
}
final void foo() {
System.out.println(myValue());
}
}
public class ChildClass extends MyClass {
#Override
protected String myValue() {
return "ChildClass";
}
}
and so on
This is a place where composition is better than inheritance
public class Doer{
private Doee doee;
public Doer(Doee doee){
this.doee = doee;
}
public void foo(){
System.out.println(doee.value);
}
}
public abstract class Doee{
public String value="myClass"
}
public ChildDoee extends Doee{
public String= "childClass"
}
...
//Excerpt from factory
new Doer(new ChildDoee);
I believe you are asking whether this is possible:
public class MyClass {
void foo() {
if (this instanceof childClass) // do stuff for childClass
else if (this intanceof anotherChildClass) // do stuff for that one
}
}
So the answer is "yes, it's doable", but very much advised against as it a) tries to reimplement polymorphism instead of using it and b) violates the separation between abstract and concrete classes.
You simply want value in MyClass to be different for an instance of childClass.
To do this, change the value in the childClass constructor:
public class childClass {
public childClass() {
value = "childClass";
}
}
Edited:
If you can't override/replace the constructor(s), add an instance block (which gets executed after the constructor, even an undeclared "default" constructor):
public class childClass {
{
value = "childClass";
}
}
I've a base class with a property that should be set in the derived class. I've to use annotations. How's that possible?
I know how do this with xml spring configurations, but not with annotations, because I've to write them at the property?
Here's some example code:
public class Base {
// This property should be set
private String ultimateProperty;
// ....
}
public class Hi extends Base {
// ultimate property should be "Hi" in this class
// ...
}
public class Bye extends Base {
// ultimate property should be "Bye" in this class
// ...
}
How is this possible with annotations?
Some options depending on what else Base has:
class Base {
private String ultimateProperty;
Base() {
}
Base(String ultimateProperty) {
this.ultimateProperty = ultimateProperty;
}
public void setUltimateProperty(String ultimateProperty) {
this.ultimateProperty = ultimateProperty;
}
}
class Hi extends Base {
#Value("Hi")
public void setUltimateProperty(String ultimateProperty) {
super.setUltimateProperty(ultimateProperty);
}
}
class Bye extends Base {
public Bye(#Value("Bye") String ultimateProperty) {
setUltimateProperty(ultimateProperty);
}
}
class Later extends Base {
public Later(#Value("Later") String ultimateProperty) {
super(ultimateProperty);
}
}
class AndAgain extends Base {
#Value("AndAgain")
private String notQuiteUltimate;
#PostConstruct
public void doStuff() {
super.setUltimateProperty(notQuiteUltimate);
}
}
Of course, if you really just want the name of the class there, then
class SmarterBase {
private String ultimateProperty = getClass().getSimpleName();
}
Annotations for fields are linked directly to the source code in the class. You may be able to do what you are looking for via Spring EL with-in an #Value annotation, but I think the complexity overrides the value.
A pattern you may want to consider is using #Configuration annotation to programmatically setup your application context. That way you can define what is injected into the base class.