Saturday, January 8, 2011

Target Unreachable, identifier row resolved to null !

SEVERE: Server Exception during PPR, #1
javax.el.PropertyNotFoundException: Target Unreachable, identifier 'row' resolved to null
at com.sun.el.parser.AstValue.getTarget(AstValue.java:xx)
at com.sun.el.parser.AstValue.isReadOnly(AstValue.java:xxx)
at com.sun.el.ValueExpressionImpl.isReadOnly(ValueExpressionImpl.java:xxx)
at




Have you ever seen the above exception while running the web application built on ADF? Apparently, this exception doesn’t communicate much on the root cause and noticed that developers search in dark to find a solution.

This article discusses couple of possible reasons for this error.

Incorrect Key definition for ViewOject

Consider the classic Employee - Department example.
Below diagram shows the association between Employee and Department .



Please note that Emp has Empno as Primary Key(PK) defined and Dept has Deptno as Primary Key.

Let us try visualizing User Interface for Employee. An Employee can belong to a specific Department. So let us try defining a List Of Values for the department name (Dname), which may help the user to select a valid Department for the Employee. Note that Dname doesn't belong to Emp, so we may need to join Emp with Dept based on Deptno. It means that EmpView is expected to have these two entities mapped. This can be done easily using JDeveloper by editing ViewObject and shuttling the entities based on the association between them. Now the EmpView(Employee View Object) look like as shown below. Please note that prior to Jdeveloper 11g R1 , the above action used to set Detno1 also as a one of the Key attribute in the EmpView. Wrong key setting by a developer may also trigger the same erroneous scenario. Rest of the article is based on the assumption that EmpView has two Keys defined, Empno and Deptno1(Deptno1 is from Dept entity). Please note that Deptno1 is wrongly set as key for this use case. We will see now how this incorrect key setting causes issues at runtime! Read on...



Next step is to define a LOV on Dname. If you are not familiar with LOV component then please go through the Fusion Developer's Guide for Oracle ADF . Now create a jsf page, drag and drop the EmpView as an editable table on the page. Let us see what happens when user selects value from the department( Dname ) LOV at runtime. Whenever user selects a different value from Dname LOV, Dname gets modified to reflect the newly selected value. Along with this "Deptno1" is also subject to change as both are from same View Accessor Row. Remember that Deptno1 is a one of the Key attributes (wrongly) defined for EmpView. So effectively key is getting modified here for a specific row and model layer fails to identify the row from cache thereafter. Next time onwards whenever user clicks on LOV or other fields which needs interaction with model, he may get the error: Target Unreachable, identifier 'row' resolved to null.

Solution

Solution is to remove the Key Attribute defined against Deptno1 column in EmpView. Once done this change, next time onwards, selecting value from LOV never causes Key attribute to change. So all works well as expected.


Updatable Primary Keys

In this scenario primary keys are expected to be entered by the user. User can amend the PK values while creating or editing a record. This may result in 'Target Unreachable' exception under certain circumstances as explained below.

Let us revisit our classic Employee - Department example to illustrate this scenario. Create table on jsf page based on the EmpView. Please note that Empno is updatable primary key here. Keep autosubmit="true" for key field of this table i.e. Empno. Now assume a use case where Manager field needs to be auto populated based on the value entered for Deptno. Obviously this makes us to set autosubmit="true" for Deptno field. Create new record on the table by calling ViewObject::creatinsert. As the PK for this new record is null initially, framework would go and create transient keys for the record for internal use. Once the new (empty) record is displayed on the table, user can key in values. As stated earlier, user is expected to key in values for primary key in this specific case. At this point, PK set by model layer (auto generated transient attribute) may be different from what is being displayed on the UI. So user amends Primary Key attribute, then enter value for Deptno and tabs out. Oops, You may see 'Target Unreachable' exception at this stage.



The reason is view layer passes the updated keys to model to find the row, but model knows only row with dummy transient attributes. Obviously search for rows fails and hits the above error scenario.

Solution

There are two possible work abounds for this issue. Please note that this issue is being tracked as an 'Enhancement Request' by ADF team. Once this is done below mentioned limitation are no longer valid.
1. Don't use natural primary keys in the above scenario, instead use surrogate key and let the system generates the value based on DBSequence. It implies that primary key for the record will never change during the transaction.

2. If the use case permits, don’t use auto submit for all the fields of the record. So there is no need to find the rows while editing. Here, we are just avoiding the error condition, though bug still live behind the screen.

PS: The above-mentioned 'erroneous scenario' may occur in all cases wherever user modifies Primary Key. One example could be the case where 'return value' from LOV is being mapped to Key attributes of row. In this case, as and when the selection changes for LOV, key attribute gets modified and which effectively causes the above exception.

1 comment:

  1. Hi.
    Great tips here, I would just like to add that I was getting a "target unreachable" error, because I was using the wrong scope. After changing from backingBeanScope to PageFlowScope, the problem was solved.

    Thanks again

    ReplyDelete