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.

Learn More ...
There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Comments

Reena said…
very good article. Keep up the good work.

Thanks,
Ree
Anonymous said…
Thank you, useful solution
Hasim said…
Nice Article and I have seen in my intial ADF development this issue and I cannot figure out based on exception.

I got one more like this.

Target Unreachable, 'VOObjectQuery' return null , where VOObjectQuery is af:query component.



Hasim
X-Oraclite 2005.
Anonymous said…
i got this err msg as well.
try config ChangeEventPolicy of iterator to be "ppr".
Sumit Yadav said…
This comment has been removed by the author.
Sumit Yadav said…
Thanks for the article .

I have one question here, in an adf table, only my currently created row should be editable before we actually commit it,other rows which are already there should be disabled.
I tried using #{row.column_name!=null} in the read only property of the column , it works cool, but the catch is the moment i select the currently created column_name (say responsibility_name),the same records become non-editable but my record is still to be saved yet, the user should be able to edit the record till the row is saved .

Any pointers ?
I tried with checking the state of the row, as in if it is new, unmodified or etc. bit it hold good for the collection of row not only the selected row ..
Jobinesh said…
Sumit,
>I tried with checking the state of
>the row,
Do you have any sample built using the above logic. Please send me the same, if you have. will take a look.
Anonymous said…
Is this bug fixed.
Can you provide the bug number?

Thanks
Ajay
Jobinesh said…
Its an internal ER#9016124. The 11.1.2 release addresses the Key change triggered by framework(e.g: PK populated by the ADF BC run time when you commit data through DB trigger). Its recommended to use surrogate key(generated during EO creation) if your model depends on multiple key attributes
Anonymous said…
We cannot use surrogate keys in our application.

Any idea if this bug will be back ported to 11.1.1.x series?

Thanks
Ajay
Jobinesh said…
Sorry, I may not be the right person to comment on this specific part. Please try contacting Oracle support

Disclaimer

The views expressed on this blog are my own and do not necessarily reflect the views of my employer.