Índice de contenidos
Liferay 7 y fechas
En Liferay gestionamos fechas para casi todo. Incluyo aquellas gestionadas automáticamente para temas de auditoría. A día de hoy, sobre todo cuando desarrollamos, podemos encontrarnos con algunos problemas derivados de la clase java.util.Date que Liferay sigue usando en esta versión más reciente. En este artículo “Liferay 7 y fechas” aprenderemos algunas acciones que nos ayudarán.
Cuando aquellos que trabajamos con esta herramienta, nos enteramos de que esta versión más reciente de Liferay estaría basada en Java 8 , recibimos una gran noticia porque, entre otras cosas, nos librábamos de los fastidiosos errores PermGem.
Sin embargo, nos encontramos con cosas como la siguiente: Liferay sigue usando la clase Java: java.util.Date . Si bien la clase tal cual no está considerada deprecated, si que lo están muchos de sus métodos.
Obtener la fecha de publicación de un contenido, de última modificación, etc., siempre nos devolverá un objeto Date. Tal vez queramos presentar la información que contiene con un determinado formato, hacer conversiones, manipulaciones e incluso cálculos. Según la acción que deseemos realizar, tal vez sea necesario elegir un camino u otro.
DateUtil
Prácticamente, en cualquier sitio donde preguntemos por una alternativa a java.util.Date, nos indicarán que usemos java.util.Calendar .
Liferay, tradicionalmente, provee de ciertas clases que nos ayudan en acciones comunes en nuestro trabajo con Java y aplicaciones web (como lo es Liferay). Una de esas clases es com.liferay.portal.kernel.util.DateUtil .
Es una clase que nos permite comparar fechas, obtener fechas basándose en patrones y localizada, averiguar los días días transcurridos entre fechas diferentes, formatear fechas, parsearlas, etc. Todo de forma más fácil y simple que con cualquier código Java creado desde cero.
Su uso preferente se encuentra en plantillas Freemarker o Velocity. Plantillas de theme, layouts, de aplicación, de listas de datos dinámicas o de contenidos web. Esto es así porque las clases Java y del API de Liferay están en ellas restringidas. Es cierto que modificando la configuración, podemos cambiar este comportamiento (tal como se ve en esta entrada para Liferay 6.2) pero si están accesibles las clases tipo “herramienta” como DateUtil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!-- Ejemplo de uso con Freemarker. Obtiene la fecha actual y el año actual. --> <#assign fechaActual = dateUtil.getCurrentDate() /> <#assign anioActual = dateUtil.getCurrentDate("yyyy", locale) /> /* Ejemplo de uso en Java. Formateamos una fecha. - fechaFormatear es una fecha tipo Date obtenida anteriormente. - local es un objeto tipo Locale. */ String formato = "dd/mm/yyyy, hh:mm:ss"; Date fecha = DateUtil.getDate(fechaFormatear, formato, local); |
La utilidad de esta clase es elevada. Sin embargo, podemos observar como se sigue trabajando con la clase java.util.Date. Tanto en los datos obtenidos como los parámetros de los métodos. Está bien si queremos solamente presentar algún dato tipo fecha y usar solamente las funcionalidades de DateUtil. ¿Pero y si queremos procesar la fecha de una forma determinada, hacer cálculos más complejos, etc.?
¿Echamos mano de Calendar? Insisto, estamos muy contentos con esta versión de Liferay por haber adoptado Java 8. Y esta versión de Java incluye java.time.* . Este paquete es una extensión de java.util.Date y java.util.Calendar. Es mejor usar éste y no los anteriores porque nos permite más y antes o después, las clases de Date y Calendar serán consideradas deprecated.
java.time.*
Se nos pide que nuestra aplicación web, muestre en un formulario un selector con los meses y años de publicación de unos contenidos web. Esos contenidos web deben ser únicamente de un tipo determinado de estructura.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ThemeDisplay themeDisplay= (ThemeDisplay) renderRequest.getAttribute(WebKeys.THEME_DISPLAY); long groupId= themeDisplay.getScopeGroupId(); DDMStructure estructura = null; boolean esUltimaVersion = false; LocalDate fechaArticulo = null; String[] meses = {"enero", "febrero", "marzo", "abril", "mayor", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"}; HashMap<string, int[]=""> listadoMesesAnios = new HashMap<string, int[]="">(); String claveListadoMesesAnios = ""; List<journalarticle> contenidos = null; /* Aquí se encontraría el código adicional que tuviera que estar, como obtener la estructura, los contenidos que se basan en esa estructura, etc. ... ... ... Lo obvio para centrarme en lo que nos ocupa del artículo: las fechas. */ contenidos = JournalArticleLocalServiceUtil.getStructureArticles(groupId, estructura.getStructureKey()); for(JournalArticle contenidoTmp: contenidos){ try { esUltimaVersion = JournalArticleLocalServiceUtil.isLatestVersion(groupId, contenidoTmp.getArticleId(), contenidoTmp.getVersion()); if(esUltimaVersion){ fechaArticulo = contenidoTmp.getDisplayDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); claveListadoMesesAnios = meses[fechaArticulo.getMonthValue() - 1] + " " + fechaArticulo.getYear(); if(!listadoMesesAnios.containsKey(claveListadoMesesAnios)){ listadoMesesAnios.put(claveListadoMesesAnios, new int[]{fechaArticulo.getMonthValue(), fechaArticulo.getYear()}); } } } catch (PortalException e) { e.printStackTrace(); } }</journalarticle></string,></string,> |
El ejemplo solamente muestra el uso, lo que necesariamente no quiere decir que esta sea la solución definitiva a este problema que expone el ejemplo. Ya sabéis cómo es esto de la programación.
¿Cuándo uso cada cosa?
Como siempre, según lo que necesitemos. Si tenemos que pasar objetos de tipo fecha a una clase del API de Liferay, evidentemente Date. Lo mismo claro está, cuando usamos los métodos de esas clases que provee Liferay y que nos devuelven fechas.
¿Tenemos que procesar esas fechas de una forma más o menos compleja?¿Uso Calendar? Calendar estuvo bien para solventar problemas de localización (o eso es lo que me ha llevado a pensar lo experimentado) pero, remarco, con Java 8, prefiero adelantarme a los acontecimientos y usar java.time.*.
Usaré entonces el paquete Time para evitar posibles deprecated actuales y futuros, cuando deba procesar esas fechas de forma compleja.
Conclusión
Es más que probable que Liferay siga con java.util.Date por motivos de compatibilidad hacia atrás y sobre todo, porque cambiar Date en su API, le supondrá un trabajo titánico. Sin embargo, en la medida de lo posible iría migrando los códigos de mis módulos y plantillas para que vayan utilizando java.time.*. Una opinión personal basada en experiencias pasadas con Liferay y alguna de sus clases.