Primefaces p: inplace: cómo propagar de manera más elegante la expresión EL para que la entidad se fusione

Me gustaría compartir el siguiente "hack" poderoso para llegar a una entidad cuyo valor ha sido editado usando p: inplace.

Mi pregunta es sobre cómo lograr esto de manera más elegante utilizando otros atributos existentes de p: inplace o de otro tipo.

El truco se adapta de una sugerencia de BalusC en Stackoverflow:

JSF (y PrimeFaces) Cómo pasar un parámetro a un método en ManagedBean

La pregunta allí implica llegar a un objeto Employee que tiene una p: edición in situ # {emp.firstName}:

<h:outputText value="First name:"/>
<p:inplace id="firstname" editor="true">
 <p:ajax event="save" onsuccess="#{employeeController.saveName()}"/>
 <p:inputText id="firstName" value="#{emp.firstName}"  
              required="true" label="text"
              valueChangeListener="#{employeeController.firstNameChanged}">
 <p:ajax event="valueChange" listener="#{employeeController.onValueChangedStart}"/>
 </p:inputText>
</p:inplace>

La sugerencia de BalusC es:

Suponiendo que está de hecho dentro de un componente de repetición en el que # {emp} ha sido expuesto por su atributo var, simplemente puede capturarlo desde el ámbito EL dentro del oyente de cambio de valor de la siguiente manera:

FacesContext context = FacesContext.getCurrentInstance();
Employee employee = context.getApplication().evaluateExpressionGet(context, "#{emp}", Employee.class);
Long id = employee.getId();

El problema con esto es que la expresión EL (en este caso # {emp}) está codificada, por lo que no es reutilizable.

Ahora estoy usando la ID de p: inplace con éxito para propagar una cadena que se puede analizar como una expresión EL para una entidad dentro de un oyente, sin embargo, dado que uno no puede usar un punto '.' En una cadena de identificación, tengo que traducir cada '.' como un hiphen '-' y luego conviértalo en una expresión EL válida en el oyente. De esta manera puedo propagar expresiones EL muy complicadas y luego saber qué entidad se debe fusionar en la base de datos (o cualquier operación de persistencia requerida).

public static String policy_convert_id_to_el_expression(String $id) {
    if ($id == null) {
        throw new IllegalArgumentException("null String $id");
    }
    return $id.replaceAll("-", ".");
}

Tengo una familia de entidades de valores profundos que envuelven valores superficiales específicos como BooleanValue, FloatQuantity, etc., cada uno con un método getValue () específicamente escrito y un método getObject () genérico y transitorio, y que llevan otros metadatos persistentes sobre el valor de poca profundidad envuelto (tales como unidades, autor, etc.).

Tengo un bean de respaldo ValueManager con:

public void onInplaceSaveEvent(AjaxBehaviorEvent ae) {
    UIComponent component = ae.getComponent();
    String id = component.getId();
    String $el = policy_convert_id_to_el_expression(id);
    FacesContext context = FacesContext.getCurrentInstance();
    Value v = context.getApplication().evaluateExpressionGet(context, "#{" + $el + "}", Value.class);
..
// merge Value entity to database (catches change to shallow wrapped value) 
// and/or perform other persistence operations such as metadata updates
..

}

Esta es ahora una estrategia altamente reutilizable.

Por ejemplo, tengo una entidad OfficeBuilding con List getFloors () y cada BuildingFloor tiene una entidad profunda de FloatQuantity getArea (), donde FloatQuantity extiende el valor.

En una tabla de datos, itero con var = floor sobre value = # {officeBuilding.floors} y edito in situ el .value superficial del área, por lo tanto:

<p:inplace 
 id="floor-area" 
 editor="true" 
 emptyLabel="UNDEF"
>
 <p:ajax 
  event="save" 
  update="@form" 
  listener="#{valueManager.onInplaceSaveEvent}"
  process="@this floor-area-value"
 />
 <p:inputText 
  id="floor-area-value" 
  value="#{floor.area.value}" 
 />
</p:inplace>

Esto se puede encapsular como un recurso compuesto / reutilizable y conveniente recursos / util / inplaceValue.xhtml por lo tanto:

<cc:interface>
  <cc:attribute name="value" type="com.example.entity.value.Value" required="true"/>
  <cc:attribute name="elid" required="true"/>
</cc:interface>

<cc:implementation>
    <p:inplace 
        id="#{cc.attrs.elid}" 
        editor="true" 
        emptyLabel="UNDEF"
        >
        <p:ajax 
            event="save" 
            update="@form" 
            listener="#{valueManager.onInplaceSaveEvent}"
            process="@this #{cc.attrs.elid}-value"
            />
        <p:inputText 
            id="#{cc.attrs.elid}-value" 
            value="#{cc.attrs.value.value}"                
            />
   </p:inplace>
</cc:implementation>

Usando el ejemplo anterior, esto se llama como:

<util:inplaceValue elid="floor-area" value=#{floor.area}/>

Solo hay que recordar que hay que tener cuidado al especificar el atributo elid de todas las apariciones de "." en la expresión EL se traducen a hiphen "-", pero funciona como un encanto para una amplia gama de casos complejos, y ahorra una gran cantidad de codificación. Es bastante elegante, pero sigue siendo un hack.

P: ¿Cómo podría uno propagar mejor al oyente la expresión EL necesaria para acceder a la entidad cuyo valor ha sido editado?

tengo tambiénhizo una sugerencia de características de Primefaces para un nuevo atributo para p: inplace específicamente para este propósito.

Respuestas a la pregunta(0)

Su respuesta a la pregunta