Optimizando Converter con Primefaces selectOneMenu y Autocomplete
Published: 2024-01-12 14:58:40

Para optimizar los converter cuando utilizamos componentes como <p:selectOneMenu> podemos recurrir a crear un services que contenga la lista de objetos a utilizar y hacemos la conversión buscando en esa lista en lugar de realizar una consulta al microservicios que devuelve el resultado, esto mejora el desempeño de la aplicación y reduce la cantidad de peticiones al microservicio.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i0pvri3017ajjcferi09.png)


## Converter

El Converter lo usaremos para selectOneMenu y Autocomplete de Primefaces. Por lo tanto recibirá una lista de objetos delimitados por la cantidad máxima que se especifique en la variable de configuración en el archivo microprofile-config.properties denominada: #-- converter

```
converter.max.number.of.elements =25
```
Como valor predeterminado serán 25 elementos. Para evitar cargar listas muy grandes. 
Cuando se realiza una selección en un selectOneMenu o Autocomplete de un elemento que excede los 25 se buscara en el microservicio, en caso contrario se buscara en la lista almacenada en la memoria.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvo3kz4135jrmtv3hjik.png)






Crear el Services




```java
@ViewScoped
@Named
public class TipoTarjetaConverterServices implements Serializable {

    @Inject
    TipotarjetaServices tipotarjetaServices;

    List<Tipotarjeta> tipotarjetas = new ArrayList<>();

    public List<Tipotarjeta> getTipotarjetas() {
        return tipotarjetas;
    }

    public void setTipotarjetas(List<Tipotarjeta> tipotarjetas) {
        this.tipotarjetas = tipotarjetas;
    }

    // <editor-fold defaultstate="collapsed" desc="Optional<Tipotarjeta> get(Long id)">
    public Optional<Tipotarjeta> get(Long id) {
        Optional<Tipotarjeta> result;

        try {
        
            result = tipotarjetas.stream().filter(x -> x.getIdtipotarjeta().equals(id)).findFirst();
            if (!result.isPresent()) {
                Tipotarjeta tipotarjeta = tipotarjetaServices.findByIdtipotarjeta(id);
                if (tipotarjeta != null) {
tipotarjetas.add(tipotarjeta);
                    return Optional.of(tipotarjeta);
                }
                result = Optional.empty();
            }
            return result;
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }
        return Optional.empty();

    }
// </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="void add(List<Tipotarjeta> tipotarjetas)">

    public void add(List<Tipotarjeta> tipotarjetas) {
        try {
            destroyed();
            this.tipotarjetas = tipotarjetas;
           
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

    }
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="void destroyed()">
    public void destroyed() {
        try {
            this.tipotarjetas = new ArrayList<>();
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

    }
// </editor-fold>

}

```

Crear el Converter
```java
@Named
@FacesConverter(forClass = Tipotarjeta.class, managed = true)
public class TipotarjetaConverter implements Converter<Tipotarjeta> {

    @Inject
    TipoTarjetaConverterServices tipoTarjetaConverterServices;

    // <editor-fold defaultstate="collapsed" desc="String getAsString(FacesContext fc, UIComponent uic, Tipotarjeta t)">
    @Override
    public String getAsString(FacesContext fc, UIComponent uic, Tipotarjeta t) {
        try {
            if (t == null) {
                return "";
           }
            if (t.getIdtipotarjeta() != null) {
                return t.getIdtipotarjeta().toString();
            }
        } catch (Exception e) {
            new FacesMessage("Error en converter  " + e.getLocalizedMessage());
        }
        return "";
    }
    // </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Tipotarjeta getAsObject(FacesContext fc, UIComponent uic, String submittedValue)">

    @Override
    public Tipotarjeta getAsObject(FacesContext fc, UIComponent uic, String submittedValue) {
        Tipotarjeta result = new Tipotarjeta();
        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }

        try {
            Integer id = Integer.parseInt(submittedValue);
            Long idTipotarjeta = id.longValue();
            Optional<Tipotarjeta> optional = tipoTarjetaConverterServices.get(idTipotarjeta);
            if (optional.isPresent()) {
                result = optional.get();
            }
            return result;
        } catch (Exception e) {

            System.out.println("====================");
            System.out.println(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
            ConsoleUtil.test("\t " + FacesUtil.nameOfClassAndMethod() + " submittedValue " + submittedValue);
            System.out.println("====================");
            throw new ConverterException(new FacesMessage(submittedValue + " is not a valid selecction from Converter"), e);
        }
    }
// </editor-fold>
}


```
## SelectOneMenu
Para el selectOneMenu se pasa la lista completa al services.

En la clase Faces

Necesita agregar en su clase

```Java
    // # Converter
     @Inject
    private Config config;

     @Inject
    @ConfigProperty(name = "converter.max.number.of.elements")
    private Provider<Integer> converterMaxNumberOfElements;

```


```java
@Inject
TipoTarjetaConverterServices tipoTarjetaConverterServices;
/**
 * invoca al método para cargar la lista en el ConverterServices
 */
    @PostConstruct
    public void init() {
        try {
 loadTipotarjetaByProyecto(proyectoSelected);

 } catch (Exception e) {
            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

}

/**
Carga la lista de tipotarjeta en el ConverterServices
*/
private void loadTipotarjetaByProyecto(Proyecto proyecto) {
        try {
          tipoTarjetaConverterServices.add(tipotarjetaServices.loadTipotarjetaByProyecto(proyecto))
            );

        } catch (Exception e) {
            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }
    }
/**

/**
 * Limpia la lista
 */
@PreDestroy
public void preDestroy() {
  tipoTarjetaConverterServices.destroyed();
}

```

En las paginas xhtml

```xhtml

 <p:selectOneMenu  value="#{tableroFaces.tarjetaSelected.tipotarjeta}" 
var="item">
                                        
<f:selectItems value="#{tipoTarjetaConverterServices.tipotarjetas}" 
 var="item" 
 itemLabel="#{item.tipotarjeta}"                                                    itemValue="#{item}"

 />
<p:column>
<i class="#{item.tipotarjeta}" /> #{item.tipotarjeta} 
</p:column>


</p:selectOneMenu>

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bahnkgo1hymch2lmwfg8.png)



## Autocomplete

Pasamos el máximo de registros permitidos que se configuraron en el archivo microprofile-config.properties. Mediante el método:
```java
calcularConverterMaxNumberOfElements(result.size(),converterMaxNumberOfElements.get())
```



```java
  // <editor-fold defaultstate="collapsed" desc="List<Tipotarjeta> completeTipotarjeta(String query)">
    public List<Tipotarjeta> completeTipotarjeta(String query) {

        List<Tipotarjeta> result = new ArrayList<>();
        try {
            query = query.trim();
            result = tipotarjetaServices.likeByTipotarjeta(query);
                                   
            tipoTarjetaConverterServices.add(result.subList(0,                     
                    calcularConverterMaxNumberOfElements(result.size(),converterMaxNumberOfElements.get()))
            );
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

        return result;
    }


```


En la pagina xhtml

```hmtl

 <p:autoComplete id="tipotarjeta" 
  multiple="false"
  value="#{tipoTarjetaFaces.tipotarjetaSelectedAutocomplete}"
                                                        
  completeMethod="#{tipoTarjetaFaces.completeTipotarjeta}"
                                                        
  var="tipotarjeta"
  itemLabel="#{tipotarjeta.tipotarjeta}" 
                                                        
  itemValue="#{tipotarjeta}"
                                                        
   forceSelection="true"
                                                        
  title="#{msg['autocomplete.minimo3caracteres']}"
                                                        
  dropdown="true"
                                                        
  minQueryLength="3"
                                                        
  scrollHeight="250"
                                                      
  converter="#{tipotarjetaConverter}"
>

<p:column>
    <h:outputText style="vertical-align: middle; margin-left: .5rem" value="#{tipotarjeta.tipotarjeta} - #{tipotarjeta.grupoTipoTarjeta.grupoTipoTarjeta}"/>
</p:column>

<p:ajax event="itemSelect"  
  listener="#{tipoTarjetaFaces.autocompleteSelectedEvent}"  
  update=":form:growl, tipotarjeta, dataTable" />  
  
<p:ajax event="itemUnselect" 
  process="@this" 
  listener="#{tipoTarjetaFaces.autocompleteUnselectListener}" 

 update=":form:growl, tipotarjeta, dataTable"
 />
 </p:autoComplete>


```