2012. március 13., kedd

Applying Generics to ADF BC View Objects

Oh well. This is my first post intended for the audience, and not just as a note for myself.
Instead of long introductions, let's get into it immediately. ;)

So this post is about why and how to apply Java generics to ADF BC, more specifically to the view objects, in order to work with them programmatically in a safer and more convenient way.

The problem

If you are working with view objects and view rows programmatically when using ADF BC, e.g. working with rows which are retrieved from a view object, then you may have a lot of code similar to the following snippets.

DepartmentsViewImpl deptVO = appModule.getDepartmentsView1();
while (deptVO.hasNext) {
    // Note that you have to cast the row even though the VO is a DepartmentsViewImpl
    // which always returns DepartmentsViewRow instances. 
    DepartmentsViewRow dept = (DepartmentsViewRow)deptVO.next();
    // Do something with dept, e.g. you want to use the generated
    // type-safe methods on the row.
    Number deptID = dept.getId();
    ...
}

Key key = ...;
// You cannot even do this, because the returned object will always be an array of Rows.
DepartmentsViewRow[] foundDepts = (DepartmentsViewRow[])deptVO.findByKey(key, 100);
// Instead you have to cast each Row separately...
Row[] foundDepts = deptVO.findByKey(key, 100);
for (Row row : foundDepts) {
    DepartmentsViewRow dept = (DepartmentsViewRow)row;
    Number deptID = dept.getId();
    ...
}

Here basically you don't have too much compile-time type-safety, and it is error-prone in the sense that you always have to take care to do the proper casts. Moreover, after a while it just feels inconvenient and cumbersome, and can get really annoying. At some point you will have to cast the Row instances to the actual row types if you want to code to the interfaces.

Wouldn't it be nice to write just something like this?

DepartmentsViewImpl deptVO = appModule.getDepartmentsView1();
while (deptVO.hasNext) {
    DepartmentsViewRow dept = deptVO.next();
    // Do something with dept
    Number deptID = dept.getId();
    ...
}

Key key = ...;
DepartmentsViewRow[] foundDepts = deptVO.findByKey(key, 100);
for (DepartmentsViewRow dept : foundDepts) {
    // Do something with dept
    Number deptID = dept.getId();
    ...
}


So you might wonder:
  • Why do I always have to cast oracle.jbo.Row to my row class when iterating through row sets, finding rows etc.? Is there no way to avoid this cumbersome code?
  • Why can't I have more compile-time safety when using specific types of view objects? Why is it the developer and not the framework or the design-time tools that need to take care of proper casts?
  • Why is there no (compile-time) relation between the VO and Row types, even if in most cases they have a one-to-one relation?
  • And here we arrive to the question in general: Why is there no Java generics applied to ADF BC at all? Even though the view objects seem a very straightworward candidate to use generics. (Well, most of the row related classes seem good candidates, e.g. Row, ViewObject, RowIterator, RowSet, RowSetIterator. But for other than the ViewObject, I cannot see an easy solution like the one desribed below.)

The idea

Well, until generifying the ADF BC code eventually happens (if ever), we can use a simple workaround to have generic methods in our view objects.
The idea is to have a generic ViewObject class with the row type as type parameter, and to override the VO methods to return instances of our parameterized view row type. Thanks to covariant return types introduced in Java 5, we can actually do this.

Here are the main steps to achieve this:
  1. Create a generic ViewObject interface extension with overridden methods (using covariant return types)
  2. Extend the framework-provided ViewObjectImpl to implement our generic interface (and implement the overridden methods appropriately)
  3. In the actual VO classes (e.g. DepartmentsViewImpl) extend this base class using the appropriate (row) type parameter

Note that using the interface in the first step is optional; and doing the implementation in a separate base class helps us avoid coding it in every actual VO class.

Details of the solution

The steps are detailed below including code snippets.

Create our custom generic interface called GenericViewObject extending the ViewObject interface like this:
public interface GenericViewObject<T extends Row> extends ViewObject {

    @Override
    public T getCurrentRow();

    @Override
    public T next();

    @Override
    public T[] findByKey(Key key, int i);

    @Override
    public T[] getAllRowsInRange();

    // similar overridden signatures for all the methods having return types of Row or Row[]
    ...

}

In the corresponding implementation class (the ViewObjectImpl extension called GenericViewObjectImpl) we can safely cast the Row instances to the actual row type (T) as we know that the VO implementation will return instances of that specific row type.

However, we have a problem when returning arrays of Rows: we cannot cast them to T[], as no matter what the type of the contained Rows is, this will always be just an array of Rows, i.e. a Row[] instance. So we have to find a way to convert the Row[] instance to a T[] instance. The problem with this is that we have to create a new array using reflection (Array.newInstance()), because you cannot instantiate a generic array. In order to do that, we have to know row class, but (in almost all cases) there is no way to get the actual type argument of a generic class at runtime. However, there is one exception to this rule: we can get the actual type arguments of a generic superclass from a subclass. And fortunately this is exactly the case when extending our generic VO base class.

See the code below on how to do that, and store the class token in order to use it later when instantiating new arrays of our type parameter.

public abstract class GenericViewObjectImpl<T extends Row> extends ViewObjectImpl implements GenericViewObject<T> {

    private Class<T> rowClass;
    
    public GenericViewObjectImpl(String string, ViewDefImpl viewDefImpl) {
        super(string, viewDefImpl);
        storeClassToken();
    }

    public GenericViewObjectImpl() {
        super();
        storeClassToken();
    }
    
    /**
     * Get the class token of the actual type argument and store it for later use.
     */
    private final void storeClassToken() {
        // When called from a subclass, this will be GenericViewObjectImpl
        // containing the type parameter.
        ParameterizedType superClass = (ParameterizedType)this.getClass().getGenericSuperclass();
        // The first and only type parameter is the row class.
        this.rowClass = (Class<T>)superClass.getActualTypeArguments()[0];
    }

    /**
     * Convert an array of Rows to an array of the generic type of this class.
     * 
     * @param rows array of rows
     * @return generic array of rows
     */
    private final T[] convertToGenericArray(Row[] rows) {
        if (rows==null) {
            // khm... array-valued method returns null,
            // but it's what super does if we have null here...
            return null;
        }
        T[] genericRows = (T[])Array.newInstance(this.rowClass, rows.length);
        for (int i = 0; i < rows.length; i++) {
            genericRows[i] = (T)rows[i];
        }
        return genericRows;
    }

    @Override
    public T getCurrentRow() {
        return (T)super.getCurrentRow();
    }

    @Override
    public T next() {
        return (T)super.next();
    }

    @Override
    public T[] findByKey(Key key, int i) {
        return convertToGenericArray(super.findByKey(key, i));
    }

    @Override
    public T[] getAllRowsInRange() {
        return convertToGenericArray(super.getAllRowsInRange());
    }

    // similarly for all the other methods
    ...

}

That's all.

Now all you have to do is replace the extends clauses in your view objects, e.g. instead of
public class DepartmentsViewImpl extends ViewObjectImpl {}
...you can write:
public class DepartmentsViewImpl extends GenericViewObjectImpl<DepartmentsViewRow> {}

After this you can start accessing your view rows from your view objects as described above, e.g.:
DepartmentsViewImpl deptVO = appModule.getDepartmentsView1();
while (deptVO.hasNext) {
    DepartmentsViewRow dept = deptVO.next();
    // Do something with dept
    Number deptID = dept.getId();
    ...
}

I hope this will be useful for some of you, or at least to start some discussion about Java generics regarding ADF BC. Your comments are much appreciated.

Cheers. :)

41 megjegyzés:

  1. Hi Patrik,

    great and useful solution! Hopefully Oracle will take a look and implement more "state of the art techniques" into the ADF product ;)

    VálaszTörlés
  2. Hi Patrik,

    On a related note, check out ER 12320395(JDEVELOPER SHOULD PROVIDE SYNTAX HELP USING GENERIC IN ADF BC)

    Thanks

    VálaszTörlés
  3. perfect explanation about java programming .its very useful.thanks for your valuable information.best java institute in chennai | best java training in velachery

    VálaszTörlés
  4. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Java developer learn from Java Training in Chennai. or learn thru Java Online Training India . Nowadays Java has tons of job opportunities on various vertical industry.

    VálaszTörlés
  5. Thank you for this post. Thats all I are able to say. You most absolutely have built this blog website into something speciel. You clearly know what you are working on, youve insured so many corners.thanks
    Digital Marketing Training in Chennai

    Digital Marketing Training in Bangalore

    digital marketing training in tambaram

    digital marketing training in annanagar

    VálaszTörlés
  6. Great post! I am actually getting ready to across this information, It’s very helpful for this blog.Also great with all of the valuable information you have Keep up the good work you are doing well.
    Digital Marketing online training

    full stack developer training in pune

    full stack developer training in annanagar

    full stack developer training in tambaram

    VálaszTörlés
  7. A universal message I suppose, not giving up is the formula for success I think. Some things take longer than others to accomplish, so people must understand that they should have their eyes on the goal, and that should keep them motivated to see it out til the end.
    python training institute in chennai
    python training in Bangalore
    python training in pune

    VálaszTörlés
  8. Thank you for allowing me to read it, welcome to the next in a recent article. And thanks for sharing the nice article, keep posting or updating news article.
    Blueprism training in tambaram

    Blueprism training in annanagar

    Blueprism training in velachery

    VálaszTörlés
  9. Nice tutorial. Thanks for sharing the valuable information. it’s really helpful. Who want to learn this blog most helpful. Keep sharing on updated tutorials…
    Data Science training in kalyan nagar
    Data Science training in OMR
    selenium training in chennai
    Data Science with Python training in chenni
    Data science training in velachery

    VálaszTörlés
  10. This is such a good post. One of the best posts that I\'ve read in my whole life. I am so happy that you chose this day to give me this. Please, continue to give me such valuable posts. Cheers!
    java training in jayanagar | java training in electronic city

    java training in chennai | java training in USA

    VálaszTörlés
  11. Your very own commitment to getting the message throughout came to be rather powerful and have consistently enabled employees just like me to arrive at their desired goals.

    angularjs Training in bangalore

    angularjs Training in btm

    angularjs Training in electronic-city

    angularjs online Training

    angularjs Training in marathahalli

    VálaszTörlés
  12. Whoa! I’m enjoying the template/theme of this website. It’s simple, yet effective. A lot of times it’s very hard to get that “perfect balance” between superb usability and visual appeal. I must say you’ve done a very good job with this.

    AWS Training in Bangalore | Amazon Web Services Training in bangalore , india

    AWS Training in pune | Amazon Web Services Training in Pune, india

    AWS Training in Chennai|Amazon Web Services Training in Chennai,India


    aws online training and certification | amazon web services online training ,india

    VálaszTörlés
  13. This is a terrific article, and that I would really like additional info if you have got any. I’m fascinated with this subject and your post has been one among the simplest I actually have read.

    Java training in Chennai

    Java training in Bangalore

    VálaszTörlés
  14. Do you want to play in an online casino? Try with us, do not be shy. perfect internet casino gambling There is such a stream of money that even your grandchildren will be enough)

    VálaszTörlés
  15. After reading this web site I am very satisfied simply because this site is providing comprehensive knowledge for you to audience.
    Thank you to the perform as well as discuss anything incredibly important in my opinion. We loose time waiting for your next article writing in addition to I beg one to get back to pay a visit to our website in




    Selenium training in bangalore
    Selenium training in Chennai
    Selenium training in Bangalore
    Selenium training in Pune
    Selenium Online training

    VálaszTörlés
  16. Эксклюзивная лента светодиодная для подсветки дизайнерского освещения и уникальных светильников я обычно беру у Ekodio

    VálaszTörlés
  17. I found your blog while searching for the updates, I am happy to be here. Very useful content and also easily understandable providing.. Believe me I did wrote an post about tutorials for beginners with reference of your blog. 
    Microsoft Azure online training
    Selenium online training
    Java online training
    Java Script online training
    Share Point online training

    VálaszTörlés
  18. Really very nice blog information for this one and more technical skills are improve,i like that kind of post.
    devops online training

    aws online training

    data science with python online training

    data science online training

    rpa online training

    VálaszTörlés
  19. Attend The Python Training in Bangalore From ExcelR. Practical Python Training in Bangalore Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Python Training in Bangalore.

    VálaszTörlés
  20. Buy your products online at low rates in Auckland Newzealand.We Provide you quality household items, outdoor furniture nz, gazeboz nz, items and all the items at low rates.

    VálaszTörlés
  21. Home Mart is a site about Home Improvement, Furniture, Home Appliances and many more.
    Check out the best
    Electronics
    home office desks nz
    coffee table nz
    bookshelves
    balance bike

    VálaszTörlés
  22. Attend The Digital Marketing courses in bangalore From ExcelR. Practical Digital Marketing courses in bangalore Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Digital Marketing courses in bangalore.
    Digital Marketing Courses in Bangalore

    VálaszTörlés
  23. cool stuff you have and you keep Python classes in pune overhaul every one of us

    VálaszTörlés
  24. Awesome post sir,
    really appreciate for your writing. This blog is very much useful...

    Hi guyz click here Digital Marketing Training in Bangalore to get the best knowledge and details and also 100% job assistance hurry up...!!

    DO NOT MISS THE CHANCE...

    VálaszTörlés
  25. thanks for your information really good and very nice web design company in velachery

    VálaszTörlés
  26. Your info is really amazing with impressive content..Excellent blog with informative concept. Really I feel happy to see this useful blog, Thanks for sharing such a nice blog..
    If you are looking for any Big data Hadoop Related information please visit our website hadoop classes in pune page!

    VálaszTörlés
  27. thanks for Sharing such an Awesome information with us.

    I learned World's Trending Technology from certified experts for free of cost.i Got job in decent Top MNC Company with handsome 14 LPA salary, i have learned the World's Trending Technology from Python training in pune experts who know advanced concepts which can helps to solve any type of Real time issues in the field of Python. Really worth trying Freelance seo expert in bangalore

    VálaszTörlés
  28. Awesome post. I am a normal visitor of your blog and appreciate you taking the time to maintain the excellent site. I’ll be a frequent visitor for a long time.

    ACP Sheet
    ACP Sheet Price
    Aluminium Composite Panel

    VálaszTörlés
  29. Attend The Data Analytics Courses Online From ExcelR. Practical Data Analytics Courses Online Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Data Analytics Courses Online.
    ExcelR Data Analytics Courses Online

    VálaszTörlés
  30. I learned World's Trending Technology from certified experts for free of cost. I Got a job in decent Top MNC Company with handsome 14 LPA salary, I have learned the World's Trending Technology from Data Science Training in btm experts who know advanced concepts which can help to solve any type of Real-time issues in the field of Python. Really worth trying Freelance seo expert in bangalore

    VálaszTörlés
  31. What an excellent informative blog, really helpful. Thank you so much for sharing such a wonderful article with us.keep updating!!
    Machine Learning Course Bangalore

    VálaszTörlés