Working with the Array Data Type in a Table

In this post I would like to follow up on my previous article about Oracle collection data types and I am going to focus on working with oracle.jbo.domain.Array attributes in af:table component.

So, in my database I have the following SQL type:

 
 
 
 
 

create or replace type varchar2_array_type as table of varchar2(200)  

And I’ve got the following table:

create table testarray (
SomeField Number,
ArrValue VARCHAR2_ARRAY_TYPE)
nested table ArrValue store as arrvalue_tab return as value;

There is an entity in ADF BC model which is based on the testarray table:

Screen Shot 2014-04-25 at 5.06.18 PM

The data type of the attribute Arrvalue is oracle.jbo.domain.Array. 

There is a corresponding attribute binding in the binding container:

    <attributeValues IterBinding="VTestarrayIterator" id="Arrvalue">
      <AttrNames>
        <Item Value="Arrvalue"/>
      </AttrNames>
    </attributeValues>

The easiest way to display the value of this attribute could be like this:

<af:table value="#{bindings.Arrvalue.inputValue.array}" var="row" 
          id="t1">
   <af:column sortable="false" headerText="Array Values" id="c1">
      <af:inputText value="#{row}" id="ot3"/>             
   </af:column>
</af:table>

And the result looks pretty nice:

Screen Shot 2014-04-25 at 5.35.38 PM

The only problem with this approach is that the table is not updatable. It is read only one.

The EL expression “#{bindings.Arrvalue.inputValue.array}” is going to invoke the method oracle.jbo.domain.Array.getArray() which returns an immutable Object[] array and all modifications to this array will be lost.

If we need to be able to update the data in the table, we’ve got to do the following:

  1. Make a copy of the bindings.Arrvalue.inputValue.array
  2. Set this copy as table’s value
  3. At the Update Model Values phase wrap the copy back into oracle.jbo.domain.Array and put it to the Arrvalue.inputValue.

So, we are going to make a copy and keep it in a request scope managed bean:

private Object[] array = null;

private Object[] createArray() {
  JUCtrlValueBinding dcb = getArrayCtrlBinding();
  if (dcb!=null){
      Array arr = (Array) dcb.getInputValue();
      if (arr!=null) {
          array = arr.getArray();
      }          
  }
  return array;
}


public void setArray(Object[] array) {
    this.array = array;
}

public Object[] getArray() {
    return (array == null ? createArray() : array);
}

    
private JUCtrlValueBinding getArrayCtrlBinding() {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer binding = (DCBindingContainer) bc.getCurrentBindingsEntry();
  return (JUCtrlValueBinding ) binding.findCtrlBinding("Arrvalue");
}

When it comes to using this copy as table’s value, we can do the following:

  <af:table value="#{TheBean.array}" var="row" 
            id="t1"
            varStatus="status">
    <af:column sortable="false" headerText="Array Values" id="c1">
       <af:inputText value="#{TheBean.array[status.index]}" id="ot3"/>             
    </af:column>
  </af:table>

Note, that we didn’t use just #{row} as inputText’s value. It wouldn’t work, since #{row} would just return an immutable String. Instead of that we used the varStatus table attribute. The EL expression #{TheBean.array[status.index]} makes the framework able to call a corresponding setter method at the Update Model Values phase, so all modifications made in the table will be saved to the TheBean.array.

The last step is to put TheBean.array back into the attribute value at the Update Model Values phase. We can use a fake invisible inputText for that purpose:

<af:inputText value="#{TheBean.dummy}" 
              visible="false" 
              converter="EmptyConverter"
              id="it2"/>

This input text should be placed below the table on a page. The beauty of this approach is that the framework will try to update the inputText value on each request. So, the setter method TheBean.setDummy(String dummy) will be invoked on each request at the Update Model Values phase right after the table values have been saved to the TheBean.array. And at this moment we’re going to wrap the array into oracle.jbo.domain.Array and put it back to the Arrvalue.inputValue:

public void setDummy(String dummy) {
  getArrayCtrlBinding().setInputValue(new Array(array));   
  array = null;
}

The secret of this dummy inputText is hidden in the EmptyConverter:

public class EmptyConverter implements Converter {
 public Object getAsObject(FacesContext facesContext,
                           UIComponent uIComponent, String string) {
     return null;
 }

 public String getAsString(FacesContext facesContext,
                           UIComponent uIComponent, Object object) {
     return null;
 }
}

It emulates that null value has been submitted for this component with the request. On the other hand, the dummy getter always returns a not null value:

 public String getDummy() {
    return DUMMY;
 }

So, the framework has no option, but to invoke the setDummy method at the Update Model Values phase.

The sample application for this post requires JDeveloper 11.1.1.7.

That’s it!

Reference: Working with the Array Data Type in a Table from our JCG partner Eugene Fedorenko at the ADF Practice blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


eight + 6 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close