DEV Community

aristides villarreal
aristides villarreal

Posted on Edited on

Optimizando Converter con Primefaces selectOneMenu y Autocomplete

Para optimizar los converter cuando utilizamos componentes como 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

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
Enter fullscreen mode Exit fullscreen mode

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

Crear el Services

@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>

}

Enter fullscreen mode Exit fullscreen mode

Crear el Converter

@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>
}


Enter fullscreen mode Exit fullscreen mode

SelectOneMenu

Para el selectOneMenu se pasa la lista completa al services.

En la clase Faces

Necesita agregar en su clase

    // # Converter
     @Inject
    private Config config;

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

Enter fullscreen mode Exit fullscreen mode
@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();
}

Enter fullscreen mode Exit fullscreen mode

En las paginas 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>

Enter fullscreen mode Exit fullscreen mode

Image description

Autocomplete

Pasamos el máximo de registros permitidos que se configuraron en el archivo microprofile-config.properties. Mediante el método:

calcularConverterMaxNumberOfElements(result.size(),converterMaxNumberOfElements.get())
Enter fullscreen mode Exit fullscreen mode
  // <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;
    }


Enter fullscreen mode Exit fullscreen mode

En la pagina xhtml


 <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>


Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
andreas_wagner_1111e1d3c7 profile image
andreas wagner • • Edited

Copy & Paste - in your Editor:

/**
 * Abstract class for converting UI components to objects and vice versa. It
 * supports extracting data entries from <code>DataTable</code> components (both
 * standard and <code>LazyDataModel</code>), as well as selection components
 * like <code>p:selectOneMenu</code> utilizing <code>f:selectItems</code>. </br>
 * </br>
 * <b>Usage example (for Copy & Paste):</b>
 *
 * <pre>
 * @FacesConverter(value = "sampleConverter")
 * public class SampleConverter extends UiConverter<SampleType> {
 *
 *    public SampleConverter() {
 *       super(
 *             // Function to extract the ID from an object
 *             item -> item.getId(),
 *             // Function to find UI component data entries by ID
 *             (id, item) -> id.equals(item.getId()));
 *    }
 *
 * }
 *
 * </pre>
 *
 * @param <T> The type of object to be converted.
 */
public abstract class UiConverter<T> implements Converter<T> {

   private final Function<T, String> idFunction;
   private final BiPredicate<String, T> objectPredicate;

   protected UiConverter(Function<T, String> idFunction, BiPredicate<String, T> objectPredicate) {
      this.idFunction = idFunction;
      this.objectPredicate = objectPredicate;
   }

   public static <T> UiConverter<T> convert(Function<T, String> idFunction, BiPredicate<String, T> objectPredicate) {
      return new UiConverter<T>(idFunction, objectPredicate) {};
   }

   @Override
   public String getAsString(FacesContext ctx, UIComponent comp, T value) {
      if (value != null) {
         return idFunction.apply(value);
      }
      return "";
   }

   @Override
   @SuppressWarnings("unchecked")
   public T getAsObject(FacesContext ctx, UIComponent comp, String itemId) {
      if (itemId != null && !itemId.trim().isEmpty()) {
         Collection<T> items = new ArrayList<>(0);
         if (comp instanceof DataTable) {
            DataTable dataTable = (DataTable) comp;
            Object value = dataTable.getValue();
            if (value instanceof Collection) {
               // case 1: list bound to the DataTable (lazy="false")
               items = (Collection<T>) value;
            } else if (value instanceof DataModel) {
               // case 2: LazyDataModel or Standard-DataModel bound to the DataTable
               Object wrappedData = ((DataModel<T>) value).getWrappedData();
               if (wrappedData instanceof Collection) {
                  items = (Collection<T>) wrappedData;
               }
            }
         } else if (comp != null && comp.getChildren() != null) {
            // case 3: components like p:selectOneMenu using f:selectItems
            for (UIComponent uic : comp.getChildren()) {
               if (uic instanceof UISelectItems) {
                  Object selectItemsValue = ((UISelectItems) uic).getValue();
                  if (selectItemsValue instanceof Collection) {
                     items = (Collection<T>) selectItemsValue;
                     break;
                  }
               }
            }
         }
         // iterating over all resolved collection elements
         if (items != null && !items.isEmpty()) {
            for (T item : items) {
               if (item != null && objectPredicate.test(itemId, item)) {
                  return item;
               }
            }
         }
      }
      return null;
   }
}
Enter fullscreen mode Exit fullscreen mode