4

I got one thought, but not able to figure it out how to implement this.

public class BaseDomain<T>{

//Generic methods goes here

}

public class Domain1 extends BaseDomain<Domain1>{

private int id;

private String name;

//only properties should be present here

}

public class Domain2 extends BaseDomain<Domain2>{

private int id;

private String name;

//only properties should be present here

}

In above scenario, easily I can define all generic methods in base class and can use in all my domain classes by using generics. But My problem here is I want to design a mechanisim by which developer's have to define only properties in a domain class(without getters/setters) however somehow BaseDomain should provide getters/setters dynamically to each domain.

Any suggestion greatly appreciated!

Tapas Jena
  • 1,069
  • 4
  • 14
  • 23

5 Answers5

2

You can't do it with the normal features of Java.

You can use a tool like Lombok.

I personally don't like this approach, because it introduces 'magic' into your project which at some point will cause trouble, and only saves a little boilerplate code.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • For a application magic is not required but for a framework this kind of feature really help..will check Lombok – Tapas Jena May 10 '13 at 13:08
  • Upvote for the comment about the magic. I used Lombok in one project and refactored it out after some time because it was actually making more problems than it was worth the time I saved in the first place. – Joachim Rohde May 10 '13 at 17:32
  • 1
    Lombok is now (2017) stable and used in so many projects. It should be integrated into the standard Java library, because it enhances the language itself. – Brain Feb 09 '17 at 07:44
2

With Reflection you can do that.

public class BaseDomain<T>{


    public String getName() {
        return this.getClass().getField("name").get(this);
    }

    public void setName(String value) {
        this.getClass().getField("name").set(this, value);
    }

}

Note that this.getClass() will refer to the runtime class of that object, that is Domain1 for example. So, you can access the fields there, get/set values, etc.

You may need to set access privileges if you declare the properties to private or protected. It they're public, it should work.

As OP mentioned, using getDeclaredFields() will not force you to declare public fields, unfortunately you have to iterate through (or use a Map) to access the Field with a specific name.

If the field is not present in your object instance, you'll get an exception.

gaborsch
  • 15,408
  • 6
  • 37
  • 48
  • Thnx @GaborSch....The solution looks good. Using this.getClass().getFields() I can get all the fields from Implemented class and can add setters/getters to base class through reflection.....Seems that it won't work in compile time?? – Tapas Jena May 10 '13 at 13:21
  • @TapasKumarJena `public void setName(String value) { this.getClass().getField("name").set(this, value); }` – johnchen902 May 10 '13 at 13:25
  • @johnchen902 Thanks, corrected. the copy-paste devils played with me :) – gaborsch May 10 '13 at 13:27
  • @TapasKumarJena Yes, if you declare them in `BaseDomain` they should work. You could upvote & accept if it is working ;) – gaborsch May 10 '13 at 13:30
  • I'm not too familiar with AspectJ, but you can give a try to the `execution(* get*(..))` construct. But better to use some dynamic proxy – gaborsch May 10 '13 at 14:06
  • @GaborSch...your approach is working fine but forcing developer to define fields as public does not make sense....Private fields are not visible. – Tapas Jena May 10 '13 at 14:19
  • Using getDeclaredFields() instead of getFields() solves the problem. Am able to access the private fields as well. – Tapas Jena May 10 '13 at 14:34
  • @TapasJena You're right, unfortunately no method called `getDeclaredField(String name)` exists in the API. But you can maintain a cache based on the child class. – gaborsch May 10 '13 at 14:46
  • @GaborSch....Now I have method names extracted from the child class...Any reference on how to add that method to the class through reflection? – Tapas Jena May 10 '13 at 14:51
  • It depends what framework are you using. You can use Pure Java dynamic proxying http://docs.oracle.com/javase/1.3/docs/guide/reflection/proxy.html or Spring AOP http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch08s06.html , or maybe http://stackoverflow.com/questions/10765061/use-invocationhandler-and-proxy-without-using-interface You may need to introduce interfaces (and also extract them with reflection with `this.getClass().getInterfaces()`) – gaborsch May 10 '13 at 15:28
0

This sounds to me like you should use an Interface. With an interface you define the functions which must be provided, and a class which implements it, must provide them. In your code ou never reference particular classes only the interface, just like a class.

Example:

public interface MyInterface
{
     public String getName();
}

public MyClass implements MyInterface
{
    public String getName { return " test"; }
}

public OtherClass
{
    private MyInterface = new MyClass();
}

If you don't want the programmers to implement your interface, this can only be done via reflection.You could use a proxy object where you implement the getters and setters and access them via this object, like discussed here: Can a Java class add a method to itself at runtime?

Community
  • 1
  • 1
Devolus
  • 21,661
  • 13
  • 66
  • 113
  • Creating Proxy object is one way but, I hope the IDE code completion won't work as that is a runtime process. Want to implement like...developer should not feel something is missing – Tapas Jena May 10 '13 at 13:05
  • I eem to remember that Hibernate uses something similar, but I'm not sure about this and how they do it. When you create a row the object doesn't really exists and is only populated transparently at runtime, but you don't notice it when you program it. The IDE treats it like any other class. So mabye you can look there how they do this, because it sounds similar to what you intend. – Devolus May 10 '13 at 13:07
  • Use **reflection**, that's how Hibernate (and a number of other frameworks, e.g. Velocity/Freemarker) are working. See my answer for sample code. – gaborsch May 10 '13 at 13:10
0

You can't do it without some kind of preprocessor for your code. The preprocessor would parse your Java files before they are compiled, add the required methods and only then push the resulting preprocessed files to the compiler. Anyway, seeing that Java is a statically typed language - this is a very bad idea.

If you want it to be dynamic, you can use Groovy instead of Java. Groovy is a separate language which shares a lot with Java and compiles to JVM bytecode. However, it allows you to make those kind of "dynamic" methods very easily.

bezmax
  • 25,562
  • 10
  • 53
  • 84
0

Any variables, getters, and setters defined in a base class can be used in a class that extends the base class, assuming the access level modifiers allow for the usage.

Here's an example:

public class BaseClass {

    private int id;

    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

class AnotherClass extends BaseClass {

    public String getIdString() {
        return Integer.toString(getId());
    }
}

Since id was defined as private in the base class, the only way the extended class can get the id is with the public getId method. By using the getId and setId methods. the extended class can use the Id field without having to define it.

If you want the extended class to have access to the fields themselves, the fields would have to be protected, rather than private.

The extended classes only have to define the getters and setters that they themselves need. They can use the getters and setters already defined in the base class, again assuming that the access level modifiers allow for the usage.

Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111