jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] [URGENT] _at_FacesDataModel inconsistencies with the spec (Re: Get your remaining items in)

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Mon, 13 Feb 2017 17:35:39 -0500

Hi

I have been checking the related documentation of @FacesDataModel and the
unofficial explanation in:

http://arjan-tijms.omnifaces.org/2015/07/jsf-23-new-feature-registrable.html

The feature is ok from a functional perspective, it has sense, but I think
there are some inconsistencies here with the spec.

Historically there is a protected method in UIData called

    protected DataModel getDataModel()

Custom datatable components override getDataModel() or adds its custom
logic.
So far so good.

The problem is the addition of @FacesDataModel includes the concept of
register the datamodel to a type. For example:

@FacesDataModel(forClass = MyCollection.class)
public class MyCollectionModel<E> extends ListDataModel<E>

It means if UIData.getValue() has a value with type MyCollection, the value
will be wrapped in a MyCollectionModel instance. This resembles
"targetClass" for Converter instances.

But in JSF, there is an Aplication class where you can register Converter
instances to apply for an specific "targetClass" and so on. But there is
nothing for DataModel. No new methods in application, no new description
in UIData.getDataModel(), nothing. In fact, there is only this description
in the javadoc of @FacesDataModel:

"... The presence of this annotation on a class automatically registers
the class with the runtime as a DataModel that's capable of wrapping a
type indicated by the forClass() attribute. ..."

This means datatable implementations that needs to override
UIData.getDataModel() will never work properly, because there is no way
to know which classes are registered in the runtime. You'll be forced to
write the same code that scans @FacesDataModel annotations using a CDI
extension and write the same logic for yourself. Does that sound a good
practice? I don't think so.

The solution is just add these methods to Application:

/**
  * Register a new DataModel class.
  */
public void addDataModel(Class<?> forClass, String dataModelClass)

/**
  * Create a DataModel instance that wraps the passed value.
  */
public DataModel createDataModel(java.lang.Class<?> forClass, Object value)

Do we need to update faces-config.xml? Could be, but is not mandatory,
because CDI was included in JSF 2.3 as a required dependency.

regards,

Leonardo Uribe