[{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"Senior Backend Developer especializado en Java, Spring Boot y arquitectura de microservicios. Me importan la arquitectura limpia y las buenas prácticas de código — en este sitio comparto mis proyectos, las decisiones técnicas detrás de ellos y lo que estoy explorando.\nMirá mis proyectos o los posts más recientes.\n","date":null,"permalink":"https://gustavopeiretti.com/es/","section":"Gustavo Peiretti","summary":"","title":"Gustavo Peiretti"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/post/","section":"Posts","summary":"","title":"Posts"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/spring-boot/","section":"Tags","summary":"","title":"Spring Boot"},{"content":"En Spring Boot, la anotación @Autowired agrega, automáticamente mediante injection, las dependencian de otros componentes. Esta anotación es utilizada para \u0026lsquo;inyectar\u0026rsquo; una instancia de una clase dentro de otra clase.\nQue es @Autowired en Spring Boot #@Autowired es una anotación utilizada en Spring Boot para habilitar la inyección automática de dependencias.\nPermite al contenedor de Spring proporcionar una instancia de una dependencia requerida cuando se crea un bean. Esta anotación puede utilizarse en campos, constructores y métodos para que Spring proporcione las dependencias automáticamente.\nLa inyección de dependencias es un patrón de diseño en el que a los objetos se les pasan sus dependencias en lugar de crearlas internamente.\nEn Spring Boot, @Autowired se utiliza para inyectar objetos en otros objetos. Esto permite un acoplamiento suelto entre componentes y ayuda a mantener el código más mantenible.\nEjemplo de @Autowired #Veamos un ejemplo de cómo utilizar la anotación @Autowired.\nTenemos una clase CarService que necesita una instancia de EngineService para funcionar correctamente. Esta puede ser inyectada en la clase CarService usando la anotación @Autowired.\n@Service public class CarService { @Autowired private EngineService engine; public void drive() { engine.start(); } } La anotación @Autowired especifica que el contenedor Spring debe suministrar el EngineService a la clase CarService. Cuando el contenedor cree la instancia CarService, inyectará automáticamente la instancia EngineService en la clase CarService.\nTen en cuenta que para que @Autowired funcione, necesitas haber configurado correctamente el contexto de la aplicación Spring Boot con los beans necesarios definidos. Puedes definir beans anotando clases con @Component, @Service, @Repository, @Controller, o @Bean.\nUso de @Autowired en Campos Privados #Los campos privados se pueden anotar con @Autowired para que Spring inyecte una dependencia en el campo.\nAquí Spring utiliza reflection para acceder internamente a la clase e inyectar el componente en el campo.\n@Service public class CarService { @Autowired private EngineService engine; public void drive() { engine.start(); } } Uso de @Autowired en Constructores #Los constructores también se pueden anotar con @Autowired para que Spring inyecte la dependencia en la clase.\nInyectar por constructores es el uso recomendado sobre las otras formas de usar Autowired.\n@Service public class CarService { private final EngineService engine; @Autowired public CarService(EngineService engine) { this.engine = engine; } public void drive() { engine.start(); } } También de esta forma:\n@Service public class CarService { private final EngineService engine; public CarService(@Autowired EngineService engine) { this.engine = engine; } public void drive() { engine.start(); } } Uso de @Autowired en métodos Set #Los métodos Set también se pueden anotar con @Autowired para que Spring inyecte la dependencia en la clase.\n@Service public class CarService { private EngineService engine; @Autowired public void setEngine(EngineService engine) { this.engine = engine; } public void drive() { engine.start(); } } El parámetro \u0026lsquo;required\u0026rsquo; en @Autowired #Por defecto, con la anotacion @Autowired la dependencia es requerida. Pero podriamos indicar que NO es requerida, por lo que Spring dejará null la dependencia.\n@Service public class CarWithNotRequiredService { @Autowired(required = false) private EngineService engine; // This could be null ! public void drive() { if (Objects.isNull(engine)) { // prevent null pointer System.out.println(\u0026#34;Engine is null!\u0026#34;); }else { engine.start(); } } } Conclusión #@Autowired es una anotación utilizada en Spring Boot para utilizar inyección automática de dependencias en clases que necesitan otros componentes.\nPermite al contenedor de Spring proporcionar una instancia de una dependencia necesaria cuando se crea un componente. Esta anotación se puede utilizar en campos, constructores y métodos, así como con el atributo \u0026ldquo;required\u0026rdquo; para indicar si una dependencia es necesaria o no. This code is in GitHub Spring Boot Code examples\n","date":"7 mar 2023","permalink":"https://gustavopeiretti.com/spring-boot-anotacion-autowired/","section":"Posts","summary":"\u003cp\u003eEn Spring Boot, la anotación @Autowired agrega, automáticamente mediante \u003cem\u003einjection\u003c/em\u003e, las dependencian de otros componentes.\nEsta anotación es utilizada para \u0026lsquo;inyectar\u0026rsquo; una instancia de una clase dentro de otra clase.\u003c/p\u003e","title":"Spring Boot Anotación @Autowired"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/categories/spring-framework/","section":"Categories","summary":"","title":"Spring Framework"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"En Spring Boot, @Bean es una anotación a nivel de método que se utiliza para declarar un bean y registrarlo en el contenedor de Spring.\n¿Qué es @Configuration en Spring Boot? #La anotación @Configuration se utiliza en Spring Boot para indicar que una clase contiene una o más definiciones bean.\nUn bean es un objeto gestionado por el framework Spring y que puede utilizarse para proporcionar servicios o funcionalidades a otras partes de la aplicación.\nCuando una clase está anotada con @Configuration, se trata como una fuente de definiciones de beans, y cualquier método dentro de la clase que esté anotado con @Bean se utilizará para crear y configurar beans.\n@Configuration public class AppConfig { // beans definition here } ¿Qué es un Bean en Spring Boot? #Un Bean es un objeto gestionado por el framework Spring.\nEs creado, gestionado y gestionado por el contenedor de Spring. Los beans se pueden utilizar para encapsular y proporcionar servicios, utilidades y funcionalidades a otros componentes de una aplicación.\n@Bean es una anotación que se utiliza para declarar un método como bean, por lo que para crear un bean en Spring Boot basta con anotar un método con @Bean.\nEl método debe devolver un objeto que quieras registrar como bean en el contenedor de Spring.\nEl contenedor Spring gestionará entonces el ciclo de vida del bean y lo inyectará en otros componentes cuando sea necesario.\nHe aquí un ejemplo de cómo definir un bean en Spring Boot utilizando la anotación @Bean.\nNótese que esta clase está anotada con @Configuration por lo que podemos crear @Beans allí.\n@Configuration public class AppConfig { @Bean public MultiplierService multiplier() { return new MultiplierService(2); } } En este ejemplo, MultiplierService es una clase que proporciona un servicio que pueden utilizar otros componentes. El método Multiplier() está anotado con @Bean, lo que indica a Spring que lo trate como un bean. Cuando el contenedor Spring se inicia, llamará a este método para crear una nueva instancia de MultiplierService. Esta instancia será gestionada por Spring y podrá ser inyectada en otros componentes que dependan de ella.\nObserva que la anotación @Bean se utiliza dentro de una clase @Configuration, que es un tipo especial de componente Spring que define información de configuración para la aplicación.\nEsta es la clase MultiplierService que queremos añadir como un Bean en nuestra Configuration.\npublic class MultiplierService { private final int multiplier; public MultiplierService(int multiplier) { this.multiplier = multiplier; } public int multiply(int value) { return value * multiplier; } } Cómo utilizar un Bean que hemos creado #Puedes utilizar un bean que hayas creado mediante autowire en otra clase o componente.\nAquí tienes un ejemplo de Autowired del bean \u0026lsquo;MultiplierService\u0026rsquo; en nuestro \u0026lsquo;AppService\u0026rsquo;:\n@Service public class AppService { private final MultiplierService multiplierService; public AppService(@Autowired MultiplierService multiplierService) { this.multiplierService = multiplierService; } public int calculate(int aValue) { return multiplierService.multiply(aValue); } } Nota: Realmente se puede omitir @Autowired porque hasta ahora sólo tenemos un Bean definido para la clase y porque si @Autowired no está presente, Spring buscará un bean que satisfaga el constructor.\nCómo dar un nombre a un Bean #Puedes dar un nombre a un bean proporcionando un nombre a la anotación @Bean. la anotación. Este nombre se utilizará como nombre del bean en el contenedor de Spring.\n@Bean(name= \u0026#34;multiplierService\u0026#34;) public MultiplierService multiplier() { return new MultiplierService(2); } En este ejemplo, la anotación @Bean recibe el valor \u0026ldquo;multiplierService\u0026rdquo;.\nEsto se utilizará como nombre del bean en el contenedor de Spring en lugar del nombre por defecto, que es el nombre del método que declara el bean (en este caso, \u0026ldquo;multiplicador\u0026rdquo;).\nSi omites el valor de la cadena en la anotación @Bean, Spring utilizará el nombre por defecto basado en el nombre del método.\n¿Cómo llamar a un Bean por su nombre? #En Spring Boot, puedes llamar a un bean con un nombre específico utilizando la anotación @Qualifier.\nLa anotación @Qualifier se utiliza para especificar el nombre del bean que se quiere utilizar cuando hay varios beans del mismo tipo o simplemente cuando queremos declarar particularmente el bean a utilizar.\nAquí tienes un ejemplo:\nCon @Qualifier le decimos a Spring exactamente qué bean necesitamos.\n@Service public class AppService { private final MultiplierService multiplierService; public AppService(@Autowired @Qualifier(\u0026#34;multiplierService\u0026#34;) MultiplierService multiplierService) { this.multiplierService = multiplierService; } public int calculate(int aValue) { return multiplierService.multiply(aValue); } } Tenga en cuenta que el nombre indicado en la anotación @Qualifier debe coincidir con el nombre del bean que desea utilizar. Si el nombre no coincide con ningún bean del contenedor, Spring lanzará una excepción en tiempo de ejecución.\nTen en cuenta también que si sólo tienes un bean de un tipo determinado, no necesitas utilizar @Qualifier ya que Spring puede conectarlo automáticamente. Sin embargo, si tienes varios beans del mismo tipo, tienes que especificar cuál usar usando @Qualifier.\n¿Qué son los nombres de alias? #En Spring Boot, los alias son nombres alternativos que se pueden dar a un bean además de su nombre principal.\nPuedes definir nombres de alias para un bean utilizando la anotación @Bean con una cadena de nombres de alias como se muestra en el siguiente ejemplo:\n@Configuration public class AppConfig { @Bean(name = {\u0026#34;multiplierService\u0026#34;, \u0026#34;multiplierService-alias1\u0026#34;, \u0026#34;multiplierService-alias2\u0026#34;}) public MultiplierService multiplier() { return new MultiplierService(2); } } Puede utilizar cualquier número de nombres de alias para un bean, y los nombres de alias pueden ser cualquier valor de cadena válido. Cuando se hace referencia a un bean por un nombre de alias, Spring lo resuelve al bean primario con ese nombre.\n¿Qué son initMethod y destroyMethod en @Bean? #En Spring Boot, initMethod y destroyMethod son atributos opcionales de la anotación @Bean que permiten especificar métodos que deben ser llamados cuando el bean es inicializado o destruido, respectivamente.\nAquí puedes ver cómo utilizar los métodos init y destroy:\n@Configuration public class AppConfig { @Bean(name = {\u0026#34;multiplierService\u0026#34;, \u0026#34;multiplierService-alias1\u0026#34;, \u0026#34;multiplierService-alias2\u0026#34;}, initMethod = \u0026#34;init\u0026#34;, destroyMethod = \u0026#34;destroy\u0026#34;) public MultiplierService multiplier() { return new MultiplierService(2); } } En este ejemplo, el método \u0026ldquo;multiplier()\u0026rdquo; está anotado con @Bean, que incluye los atributos initMethod y destroyMethod.\nEl atributo initMethod especifica que se debe llamar a un método llamado \u0026ldquo;init()\u0026rdquo; cuando se inicializa el bean, y el atributo destroyMethod especifica que se debe llamar a un método llamado \u0026ldquo;destroy()\u0026rdquo; cuando se destruye el bean.\nEl método init() puede realizar cualquier lógica de inicialización que el bean requiera. Este método es llamado después de que el bean haya sido creado y sus dependencias hayan sido inyectadas, pero antes de que el bean esté disponible para su uso.\nEl método destroy() puede realizar cualquier lógica de limpieza que requiera el bean. Este método se ejecuta cuando el contenedor Spring se cierra o el bean es destruido por el contenedor.\nTen en cuenta que los métodos especificados en initMethod y destroyMethod deben tener un tipo de retorno void y no tomar argumentos. Si el método tiene un tipo de retorno o toma argumentos, Spring lanzará una excepción en tiempo de ejecución.\npublic class MultiplierService { private final int multiplier; public MultiplierService(int multiplier) { this.multiplier = multiplier; } public int multiply(int value) { return value * multiplier; } public void init() { System.out.println(\u0026#34;Calling init method :)\u0026#34;); } public void destroy() { System.out.println(\u0026#34;Calling destroy method :(\u0026#34;); } } Ejecutando este ejemplo: #Si ejecutamos este ejemplo completo con esta clase principal de Spring Boot:\n@SpringBootApplication public class SpringBootBeanApplication { private final AppService appService;; public SpringBootBeanApplication(AppService appService) { this.appService = appService; } public static void main(String[] args) { SpringApplication.run(SpringBootBeanApplication.class, args); } @PostConstruct public void doExamples() { System.out.println(\u0026#34;Calling bean method with this result: \u0026#34; + appService.calculate(123)); } } Podemos ver esta Salida:\nINFO 17028 --- [ main] c.g.s.SpringBootBeanApplication : Starting SpringBootBeanApplication using Java 17.0.2 with PID 17028 (C:\\dev\\spring-boot-examples\\spring-boot-bean\\target\\classes started by gustavo.peiretti in C:\\dev\\spring-boot-examples\\spring-boot-bean) INFO 17028 --- [ main] c.g.s.SpringBootBeanApplication : No active profile set, falling back to 1 default profile: \u0026#34;default\u0026#34; Calling init method :) Calling bean method with this result: 246 INFO 17028 --- [ main] c.g.s.SpringBootBeanApplication : Started SpringBootBeanApplication in 0.607 seconds (process running for 1.122) Calling destroy method :( Cuál es el ciclo de vida del @Bean #En este ejemplo, el método @Bean se define en una clase @Configuration.\n1- La definición del bean se registra en el contenedor de Spring, y el contenedor instantiza e inicializa el bean 2- Spring inyecta cualquier dependencia que el bean necesite. 3- Se llama al método Init. 3- Una vez que el bean está completamente inicializado, está disponible para su uso en la aplicación. 4- Cuando la aplicación se cierra o el bean es destruido por el contenedor, se llama al método destroy especificado en la anotación @Bean.\nAnotación ConditionalOnProperty con \u0026lsquo;Beans\u0026rsquo; Spring #La anotación @ConditionalOnProperty se utiliza para crear condicionalmente un bean Spring dependiendo de la configuración de una propiedad.\nPor ejemplo, vamos a crear un bean llamado senderMessagesSms si sender.sms tiene el valor true y en caso negativo, se creará senderMessagesEmail.\n@ConditionalOnProperty(name = \u0026#34;sender.sms\u0026#34;, havingValue = \u0026#34;true\u0026#34;) @Bean(name = \u0026#34;senderMessagesSms\u0026#34;) public SenderMessages senderMessagesSms() { return new SenderMessagesSms(); } @ConditionalOnProperty(name = \u0026#34;sender.sms\u0026#34;, havingValue = \u0026#34;false\u0026#34;) @Bean(name = \u0026#34;senderMessagesEmail\u0026#34;) public SenderMessages senderMessagesEmail() { return new SenderMessagesEmail(); } Pero, ¿qué pasa si la propiedad no existe? Para este caso podemos utilizar el parámetro matchIfMissing. Así, si la propiedad no está definida se creará el bean con ese parámetro puesto a true.\nmatchIfMissing = true @ConditionalOnProperty(name = \u0026#34;sender.sms\u0026#34;, havingValue = \u0026#34;true\u0026#34;, matchIfMissing = true) @Bean(name = \u0026#34;senderMessagesSms\u0026#34;) public SenderMessages senderMessagesSms() { return new SenderMessagesSms(); } @ConditionalOnProperty(name = \u0026#34;sender.sms\u0026#34;, havingValue = \u0026#34;false\u0026#34;) @Bean(name = \u0026#34;senderMessagesEmail\u0026#34;) public SenderMessages senderMessagesEmail() { return new SenderMessagesEmail(); } Conclusión #Este es un resumen de lo que hemos cubierto:\nEn Spring Boot, un @Bean es una anotación a nivel de método que se utiliza para declarar un bean y registrarlo en el contenedor de Spring. Un método @Bean debe definirse en una clase @Configuration, y normalmente devuelve una instancia de una clase que quieras utilizar como bean en tu aplicación. Opcionalmente, puedes especificar un nombre para el bean utilizando el atributo name de la anotación @Bean. También puedes especificar una matriz de nombres de alias para el bean utilizando el atributo value de la anotación @Bean. Puedes utilizar la inyección de dependencias para inyectar un @Bean en otra clase o componente, lo que te permitirá utilizar el bean en tu aplicación. Puedes utilizar los atributos initMethod y destroyMethod de la anotación @Bean para especificar los métodos que serán llamados cuando el bean sea instanciado y destruido. El ciclo de vida de un @Bean en Spring Boot incluye el registro, la instanciación e inicialización, la inyección de dependencias y la destrucción final. Si necesitas crear un bean bajo alguna condición utiliza la anotación ConditionalOnProperty. En conclusión, @Bean es una potente anotación de Spring Boot que permite declarar beans de forma sencilla e intuitiva. Puedes registrar y utilizar instancias de tus clases como beans en tu aplicación creando métodos @Bean en tus clases @Configuration, y puedes utilizar la arquitectura de inyección de dependencias de Spring para gestionar eficientemente las dependencias de tus componentes.\nEste código está en GitHub Spring Boot Code examples\n","date":"6 mar 2023","permalink":"https://gustavopeiretti.com/spring-boot-anotacion-bean/","section":"Posts","summary":"\u003cp\u003eEn Spring Boot, \u003ccode\u003e@Bean\u003c/code\u003e es una anotación a nivel de método que se utiliza para declarar un bean y registrarlo en el contenedor de Spring.\u003c/p\u003e","title":"Entendiendo en Spring Boot las anotaciones @Configuration y @Bean"},{"content":"@ConfigurationProperties es una característica de Spring Boot que permite vincular configuraciones externas a una clase Java.\nMapea nombres de propiedades a campos de una clase Java, facilitando la gestión de configuraciones externas.\nPor lo tanto, podemos utilizar esta funcionalidad de Spring si queremos establecer las propiedades en una clase Java.\nDependencias #Necesitará al menos esta dependencia.\n\u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; Cómo utilizar las propiedades de configuración con una clase Java Pojo #Las propiedades pueden ser especificadas desde tus archivos application.properties.\nLa clase anotada puede entonces ser usada para acceder a las propiedades en el código de tu aplicación. Esto ayuda a separar la configuración de la implementación, haciéndola más fácil de gestionar y mantener.\nHe aquí un ejemplo sencillo de cómo utilizar @ConfigurationProperties en una aplicación Spring Boot:\nSi tenemos este fichero de propiedades:\napp.name=The name of this app app.description=This description of this app Podemos establecer estas propiedades en una clase Java de forma automática. Para ello, hay que anotar la clase Java con estas dos anotaciones:\n@ConfigurationProperties @Component El prefijo en ConfigurationProperties tiene que ser igual al prefijo de la propiedad.\n@ConfigurationProperties(prefix = \u0026#34;app\u0026#34;) @Component public class AppInfo { private String name; private String description; // set and get.. @Override public String toString() { return \u0026#34;AppInfo{\u0026#34; + \u0026#34;name=\u0026#39;\u0026#34; + name + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#34;, description=\u0026#39;\u0026#34; + description + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#39;}\u0026#39;; } } Observe cómo el prefijo de la propiedad se une con la anotación y cada propiedad con el atributo class.\nCómo usar las propiedades de configuración con un Bean de Spring #Esta forma es similar a la anterior que aprendimos veamos como se utiliza.\nPor ejemplo, para estas propiedades:\napp.mail.hostname=host@mail.com app.mail.port=9000 app.mail.from=mailer@mail.com Vamos a definir la clase AppConfig y la anotamos con @Configuration. La clase AppConfig es una clase de @Configuration que define un componente con la anotación @Bean.\nEl método mailData() devuelve una instancia de MailData y se anota con @ConfigurationProperties pasando como parámetro el prefijo \u0026ldquo;app.mail\u0026rdquo; para especificar que sus atributos (los de la clase MailData) deben ser llenados con las propiedades que tienen el prefijo \u0026ldquo;app.mail\u0026rdquo;.\n@Configuration public class AppConfig { @Bean @ConfigurationProperties(prefix = \u0026#34;app.mail\u0026#34;) public MailData mailData() { MailData mailData = new MailData(); return mailData; } } Ejecución de ambos ejemplos #A continuación, puede utilizar el bean o el componente en otras partes de su aplicación a través de la inyección de dependencias, por ejemplo:\n@SpringBootApplication public class SpringBootConfigurationPropertiesApplication { @Autowired AppInfo appInfo; @Autowired MailData mailData; public static void main(String[] args) { SpringApplication.run(SpringBootConfigurationPropertiesApplication.class, args); } @PostConstruct public void post() { System.out.println(appInfo); System.out.println(mailData); } } El resultado de esto es:\nAppInfo{name=\u0026#39;The name of this app\u0026#39;, description=\u0026#39;This description of this app\u0026#39;} MailData{hostName=\u0026#39;host@mail.com\u0026#39;, port=9000, from=\u0026#39;mailer@mail.com\u0026#39;} Conclusión: #@ConfigurationProperties es una anotación de primavera utilizada para asignar propiedades de configuración externas a campos de una clase Java, facilitando la obtención de valores de propiedad en sus servicios.\nEste código está en GitHub\n","date":"8 feb 2023","permalink":"https://gustavopeiretti.com/spring-boot-configuracion-de-propiedades/","section":"Posts","summary":"\u003cp\u003e@ConfigurationProperties es una característica de Spring Boot que permite vincular configuraciones externas a una clase Java.\u003c/p\u003e","title":"Spring Boot Configuración de Propiedades"},{"content":"En este tutorial, vamos a ver cómo depurar una aplicación Spring Boot con Gradle usando la consola de línea de comandos.\nRecuerda que aprendimos en un post anterior cómo ejecutar Spring Boot. Sin embargo, es muy común ejecutar Spring Boot en modo de depuración en nuestra rutina diaria de desarrollo.\nPodemos depurar Spring Boot desde el comando de línea con este comando:\nMire este parámetro \u0026quot;-debug-jvm\u0026quot;\n./gradlew bootRun --debug-jvm Este comando iniciará Spring Boot y esperará a que conectemos nuestro IDE al puerto.\nAhora podemos abrir el IDE. En este ejemplo usamos IntelliJ.\nPara este IDE tienes que abrir el menú /run/Edit Configurations\nAhora, haga clic en el \u0026ldquo;botón más\u0026rdquo; y elija \u0026ldquo;Remote JVM Debug\u0026rdquo;\nCambie el número de puerto del mismo puerto que la consola. Lo guardas con el botón \u0026ldquo;ok\u0026rdquo;.\nDar el nombre que desea para identificar su propia opción de depuración.\nAhora puede iniciar su aplicación en modo de depuración.\nTenga cuidado de iniciar el comando primero desde la consola y luego desde su IDE.\nPuede realizar las mismas operaciones mencionadas anteriormente con los botones de la barra de herramientas.\nConclusión: #Aquí aprendimos cómo iniciar una aplicación Spring Boot en modo de depuración desde la consola de Gradle y cómo iniciar la depuración desde su IDE agregando una depuración remota de JVM.\n","date":"19 sept 2022","permalink":"https://gustavopeiretti.com/spring-boot-gradle-depuraci%C3%B3n-en-consola/","section":"Posts","summary":"\u003cp\u003eEn este tutorial, vamos a ver cómo depurar una aplicación Spring Boot con Gradle usando la consola de línea de comandos.\u003c/p\u003e","title":"How to debug Spring Boot from the Gradle command line"},{"content":"Aquí vamos a aprender el comando básico para construir y ejecutar la aplicación Spring Boot con Gradle Wrapper\nPara este post, suponemos que hemos iniciado un proyecto en Spring Boot con gradle.\nEl \u0026lsquo;wrapper\u0026rsquo; de Gradle #Puedes usar Gradle sin instalarlo en su computadora. Gradle wrapper (gradlew) es un script que puede agregar a su proyecto para ejecutarlo y compilarlo sin instalaciones externas.\nCon Gradle Wrapper puedes:\nIncluir a Gradle en su proyecto sin instalaciones externas. Cambiar la versión de Gradle para su proyecto sin afectar a otros proyectos. Añadir Gradle al control de versiones del sistema. Utilizar la versión correcta de Gradle para su proyecto. Qué es y porqué Gradle? #Gradle se utiliza para compilar, ejecutar pruebas y construir tu aplicación.\nGradle proporciona una manera fácil de crear tareas y ejecutarlas para llevar a cabo diferentes pasos en un modo ordenado y controlado.\nAl mismo tiempo, Gradle proporciona un sólido sistema de dependencias.\nAlgunas de las mejores características de Gradle son:\nPerformance: es más rápido y tiene optimizaciones continuas. JVM: Gradle se ejecuta en JVM y utiliza la API estándar de Java. Extensibilidad: Gradle proporciona tareas predefinidas, pero también puede proporcionar sus propias tareas. Soporte de IDE\u0026rsquo;s: Android Studio, IntelliJ, Eclipse, etc. tienen soporte de Gradle Convención: Gradle utiliza convenciones que le permiten adoptar rápidamente este sistema de construcción. Información (Insight): proporciona información detallada que puedes usar para entender lo que sucede con tu compilación. Carpetas y archivos de Gradle #En un proyecto Spring Boot con el sistema de compilación Gradle, tenemos estas carpetas y archivos:\ncarpeta gradle: con el código Gradle compilado build.gradle file: este es su propio archivo principal. Editamos este archivo para crear nuestras propias tareas y añadir dependencias. archivo gradlew: script bash para ejecutar Gradle en Linux gradle.bat file: script batch para ejecutar Gradle en Windows setting.gradle file: otros ajustes como el nombre del proyecto El archivo build.gradle #Dentro del archivo build.gradle, podemos observar estas secciones\nplugins: proporcionan funcionalidades como compilar código Java, ejecutar Spring Boot y establecer la estructura del proyecto.\ngroup: el grupo del que formará parte este proyecto.\nversion: la versión actual del proyecto.\nsourceCompatibility: la compatibilidad con la versión Java.\nrepositories: la sección del repositorio es el lugar desde el que indicamos desde dónde queremos descargar las dependencias\ndependencies: la sección de dependencias es donde escribimos las dependencias que requerimos para nuestro proyecto.\ntask: una tarea es una secuencia de acciones con su nombre.\nPlugins que necesitas en un proyecto Spring Boot # Spring Boot: este plugin te permite ejecutar aplicaciones Spring Boot y crear un paquete ejecutable o archivos de guerra. Spring dependency management: este es un práctico plugin que importará automáticamente las spring-boot-dependencies desde la versión de Spring Boot que esté utilizando. Te permite saltar números de versión cuando declaras dependencias. Java: este plugin proporciona todas las actividades necesarias para un proyecto Java como compilación, pruebas y capacidades de construcción. plugins{ id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.7.3\u0026#39; id \u0026#39;io.spring.dependency-management\u0026#39; version \u0026#39;1.0.13.RELEASE\u0026#39; id \u0026#39;java\u0026#39; } Comandos principales para Spring Boot y Gradle #Podemos ver un breve resumen de Gradle con información sobre la versión que tenemos en nuestro proyecto.\nLinux ./gradlew Windows gradlew.bat\nEjecutamos el comando gradlew tasks para saber qué tareas tenemos.\nSi queremos más detalles para una tarea específica, podemos ejecutar ./gradlew help \u0026ndash;task Por ejemplo ./gradlew help \u0026ndash;task bootRun\nLas tareas principales con Gradle en un proyecto Spring Boot #Para realizar estas tareas, necesitamos los plug-ins que ya mencionamos anteriormente.\nplugins{ id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.7.3\u0026#39; id \u0026#39;java\u0026#39; } Ejecutar el proyecto de Spring Boot → gradlew bootRun\nCon este comando, iniciamos nuestra aplicación en el puerto por default 8080.\nConstruir el proyecto de Spring Boot → gradlew build\nPuedes ejecutar gradlew build -i para ver más información.\nEste comando ejecutará varias tareas como configurar, descargar dependencias, compilar clases Java, ejecutar pruebas y crear archivos \u0026ldquo;jar\u0026rdquo;.\nLos archivos jar ejecutables se pueden encontrar con el nombre y la versión en la carpeta build/libs. También puede ver dentro de la carpeta build las subcarpetas con las clases compiladas, las dependencias externas y los resultados de las pruebas.\nEsto crea un archivo ejecutable Java jar.\nEl nombre proviene del archivo settings.gradle y la versión proviene de build.gradle\nLimpia el proyecto de Spring Boot → gradlew clean\nEste comando remueve la carpeta build.\nEjecutar Tests del proyecto Spring Boot → gradlew test\nEsta tarea ejecutará todos los test en tu proyecto.\n./gradlew test -i (el parámetro “-i” agrega mas información en la salida de la consola)\nObserva que en la consola tenemos los resultados del test y un informe HTML con un buen detalle.\nSi abrimos el archivo index.html en esta ubicación, podemos ver el informe.\nEste informe es muy completo y puede ayudarte si tienes muchas pruebas ejecutadas.\nConclusión: #Este post nos enseñó cómo ejecutar, construir y ejecutar pruebas en un proyecto Spring Boot con Gradle. Gradle es excelente en la gestión y construcción de tus proyectos con Spring Boot.\nReferencias:\nSpring Boot Gradle Plugin Reference Guide The Java Plugin (gradle.org)\n","date":"2 sept 2022","permalink":"https://gustavopeiretti.com/spring-boot-con-gradle-wrapper/","section":"Posts","summary":"\u003cp\u003eAquí vamos a aprender el comando básico para construir y ejecutar la aplicación Spring Boot con Gradle Wrapper\u003c/p\u003e","title":"Spring Boot with Gradle Wrapper"},{"content":"En este post, vamos a entender como enviar un email con Spring Boot.\nLa dependencia necesaria #Para enviar un email, se necesita esta dependencia.\nbuild.gradle\nimplementation \u0026#39;org.springframework.boot:spring-boot-starter-mail\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; La configuración para enviar emails en Spring #Nosotros necesitamos definir JavaMailSender si queremos establecer las propiedades programáticamente.\nTú puedes usar JavaMailSenderImpl que implementa JavaMailSender para definir la configuración del servidor de email. Por ejemplo para Gmail, la configuración podría verse así:\nimport org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; import java.util.Properties; @Configuration public class MailSenderConfig { @Bean(\u0026#34;javaMailSender\u0026#34;) public JavaMailSender javaMailSender() { JavaMailSenderImpl sender = new JavaMailSenderImpl(); sender.setHost(\u0026#34;smtp.gmail.com\u0026#34;); sender.setPort(587); sender.setUsername(\u0026#34;user@gmail.com\u0026#34;); sender.setPassword(\u0026#34;password\u0026#34;); Properties props = sender.getJavaMailProperties(); props.put(\u0026#34;mail.transport.protocol\u0026#34;, \u0026#34;smtp\u0026#34;); props.put(\u0026#34;mail.smtp.auth\u0026#34;, \u0026#34;true\u0026#34;); props.put(\u0026#34;mail.smtp.starttls.enable\u0026#34;, \u0026#34;true\u0026#34;); props.put(\u0026#34;mail.debug\u0026#34;, \u0026#34;true\u0026#34;); return sender; } } Observa. Para usar los servicios de Google SMTP tu necesitas crear una única \u0026ldquo;app password\u0026rdquo; para el servicio.\nhttps://support.google.com/accounts/answer/185833?hl=en\nConfiguración usando properties para enviar e-mails en Spring #Antes, nosotros definimos la configuración cargando las propiedades en la JavaMailSenderImpl class.\nSin embargo, podemos saltar esto y definir las propiedades directamente en el application.properties file.\nSi tú defines las propiedades, sin crear el \u0026lsquo;bean config\u0026rsquo;, Spring creará la clase JavaMailSenderImpl por ti con dichas propiedades.\nspring.mail.host=smtp.gmail.com spring.mail.port=587 spring.mail.username=user@gmail.com spring.mail.password=password spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true Enviando un email con Spring #Puedes enviar un email simple, solo texto. #La class SimpleMailMessage provee un modelo simple para enviar mensajes de solo-texto.\nSimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); message.setTo(to); message.setSubject(subject); message.setText(text); mailSender.send(message); También, puedes enviar email con archivos adjuntos. #Para enviar e-mails con archivos adjuntos necesitas dos clases.\nMimeMessage te permite el agregado de archivos adjuntos y MimeMessageHelper te ayuda a crear el mail.\nMimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(text); helper.addAttachment(attachName, inputStream); mailSender.send(message); Si tu quieres, pueden agregar HTML tags.\nPor ejemplo, aquí nosotros agregamos un texto con un tag HTML de negrita.\nMimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(\u0026#34;\u0026lt;b\u0026gt;bold message\u0026lt;/b\u0026gt;\u0026#34;, true); // text with HTML tags helper.addAttachment(attachName, inputStream); mailSender.send(message); MIME message significa “Multipurpose Internet Mail Extensions”. Con MIME messages tu puedes enviar HTML, y agregar archivos (text, audio, images, etc).\nResumen de las clases que usamos # JavaMailSender: interface para configurar Spring Email JavaMailSenderImpl: implementación de JavaMailSender SimpleMailMessage: modelo para completar los atributos necesarios para enviar un email. MimeMessage: una class que representa un mensaje de tipo MIME. MimeMessageHelper: una clase de ayuda para crear mensajes MIME. Ejemplo de un servicio usando JavaMailSender #Aquí nosotros creamos un servicio y usamos JavaMailSender que definimos previamente.\n@Service public class EmailService { private JavaMailSender mailSender; public EmailService(JavaMailSender mailSender) { this.mailSender = mailSender; } public void send(String from, String to, String subject, String text) { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); message.setTo(to); message.setSubject(subject); message.setText(text); mailSender.send(message); } public void sendWithAttach(String from, String to, String subject, String text, String attachName, InputStreamSource inputStream) throws MessagingException { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(text, true); helper.addAttachment(attachName, inputStream); mailSender.send(message); } } Testeando nuestro Servicio de Email #Con el objetivo de chequear la funcionalidad de nuestro servicio, vamos a utilizar https://greenmail-mail-test.github.io/greenmail/\nGreenMail es un open-source framework que provee test servers para validar nuestro email service construido.\nbuild.gradle\nimplementation \u0026#39;org.springframework.boot:spring-boot-starter-mail\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; testImplementation \u0026#39;com.icegreen:greenmail-junit5:1.6.9\u0026#39; Vamos a definir las propiedades de test para GreenMail.\n## test properties for test email Greenmail spring.mail.host=localhost spring.mail.port=3025 spring.mail.username=user@gmail.com spring.mail.password=password Test usando GreenMail para validar EmailService\nimport com.icegreen.greenmail.configuration.GreenMailConfiguration; import com.icegreen.greenmail.junit5.GreenMailExtension; import com.icegreen.greenmail.util.ServerSetupTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import javax.mail.internet.MimeMessage; import java.io.File; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest class EmailServiceTest { @RegisterExtension static GreenMailExtension greenMail = new GreenMailExtension(ServerSetupTest.SMTP) .withConfiguration(GreenMailConfiguration .aConfig().withUser(\u0026#34;user@gmail.com\u0026#34;, \u0026#34;password\u0026#34;)); @Autowired private EmailService emailService; @Test void send() throws Exception { emailService.send(\u0026#34;gus@gmail.com\u0026#34;, \u0026#34;jhon@gmail.com\u0026#34;, \u0026#34;Hello\u0026#34;, \u0026#34;How are you?\u0026#34;); MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); MimeMessage receivedMessage = receivedMessages[0]; assertEquals(\u0026#34;gus@gmail.com\u0026#34;, receivedMessage.getFrom()[0].toString()); assertEquals(\u0026#34;jhon@gmail.com\u0026#34;, receivedMessage.getAllRecipients()[0].toString()); assertEquals(\u0026#34;Hello\u0026#34;, receivedMessage.getSubject().trim()); assertEquals(\u0026#34;How are you?\u0026#34;, receivedMessage.getContent().toString().trim()); // others test assertions with receivedMessage.. } @Test void sendWithAttach() throws Exception { ClassPathResource classPathResource = new ClassPathResource(\u0026#34;info.txt\u0026#34;); File file = classPathResource.getFile(); FileSystemResource fileResource = new FileSystemResource(file); emailService.sendWithAttach(\u0026#34;gus@gmail.com\u0026#34;, \u0026#34;jhon@gmail.com\u0026#34;, \u0026#34;Hello\u0026#34;, \u0026#34;How are you?\u0026#34;, \u0026#34;info.txt\u0026#34;, fileResource); MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); MimeMessage receivedMessage = receivedMessages[0]; assertEquals(\u0026#34;gus@gmail.com\u0026#34;, receivedMessage.getFrom()[0].toString()); assertEquals(\u0026#34;jhon@gmail.com\u0026#34;, receivedMessage.getAllRecipients()[0].toString()); assertEquals(\u0026#34;Hello\u0026#34;, receivedMessage.getSubject().trim()); // others test assertions with receivedMessage.. } } Conclusión: #En este post nosotros aprendimos como configurar Java Email Sender con Spring Boot usando \u0026lsquo;beans\u0026rsquo; configuration y property files. También entendimos como crear un JUnit test con GreenMail.\nEl código: #El código lo encuentras en GitHub. https://github.com/gustavopeiretti/spring-boot-examples/tree/master/spring-boot-email\n","date":"25 jul 2022","permalink":"https://gustavopeiretti.com/spring-boot-enviar-emails/","section":"Posts","summary":"\u003cp\u003eEn este post, vamos a entender como enviar un email con Spring Boot.\u003c/p\u003e","title":"Como enviar emails con Spring Boot"},{"content":"Spring Boot te permite conectarte a una base de datos de forma simple y con mínimas configuraciones.\nVeamos en este post como conectarse a una base de datos.\nComo conectar Spring Boot con una base de datos #Puedes crear una conexión a una base de datos en Spring Boot con pocos pasos.\nDefine la base de datos que quieres utilizar. Incluye las dependencias. Define los parámetros de conexión en el archivo de propiedades. Define la base de datos #En este ejemplo, nosotros usaremos MySql, pero la configuración aplica a cualquier base de datos. La única diferencia es la dependencia necesaria para conectar tu base de datos con tu servicio.\nDependencias para crear la conexión con la base de datos en Spring Boot #Para crear una DB conexión, tu necesitas las siguientes dependencias.\nPara MySql necesitas:\n\u0026#39;mysql:mysql-connector-java:8.0.28\u0026#39; Para PostgreSQL:\n\u0026#39;org.postgresql:postgresql\u0026#39; Para Oracle:\n\u0026#39;com.oracle.database.jdbc:ojdbc8\u0026#39; Para MSSQL:\n\u0026#39;com.microsoft.sqlserver:mssql-jdbc\u0026#39; Los parámetros de conexión en el archivo de propiedades #En estas propiedades, nosotros primero debemos establecer el path de conexión con la DB. Luego indicamos el user y el password. Con esta minima configuración y la dependencia, ya es suficiente para Spring entender como conectarse.\nLa configuración minima para conectar a la base queda así:\nPara MySql:\nspring.datasource.url=jdbc:mysql://localhost:3306/your_database spring.datasource.username=your_user spring.datasource.password=your_password Para PostgreSQL:\nspring.datasource.url=jdbc:postgresql://localhost:5432/your_database spring.datasource.username=your_user spring.datasource.password=your_password Para Oracle:\nspring.datasource.url=jdbc:oracle://localhost:1521/your_database spring.datasource.username=your_user spring.datasource.password=your_password Para MSSQL:\nspring.datasource.url=jdbc:sqlserver://localhost:1433/your_database spring.datasource.username=your_user spring.datasource.password=your_password *Observa que el puerto y la url podrían cambiar dependiendo de la instalación de cada base de datos.\nSpring puede crear las tablas por tí #Si quieres delegar la creación de las tablas a Spring, puedes hacerlo agregando esta propiedad.\nspring.jpa.hibernate.ddl-auto=create Este property le dice a Spring si debe crear las tablas desde las entidades que hemos creado.\nEste articulo explica más acerca de esta propiedad.\nnone: no se realizará ninguna acción. drop: se crearán las tablas a partir de las entidades y al final se borrarán. create: se borrarán las tablas y al final se crearán update: realiza una actualización del esquema a partir de las entidades. validate: sólo realiza una validación entre las entidades y el esquema de la base de datos. Veamos un poco más sobre esta propiedad \u0026ldquo;spring.jpa.hibernate.ddl-auto\u0026rdquo;\nSi definimos la propiedad como \u0026ldquo;create\u0026rdquo; Spring destruirá todas las tablas y luego las creará todas nuevamente.\nPara entender más acerca de las entidades, revisa este otro post\nPor ejemplo para esta entidad. Spring hará lo siguiente:\nObserva en la consola de Spring lo que sucede con esta configuración \u0026ldquo;create\u0026rdquo;.\nPara ver las sentencias SQL en la consola, necesitas esta configuración\nspring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true Conclusión #En este post, hemos aprendido como configurar una conexión a una base de datos y como delegar la creación de la base de datos/tablas a Spring.\n","date":"23 jun 2022","permalink":"https://gustavopeiretti.com/spring-boot-database-conexion-config/","section":"Posts","summary":"\u003cp\u003eSpring Boot te permite conectarte a una base de datos de forma simple y con mínimas configuraciones.\u003cbr\u003e\nVeamos en este post como conectarse a una base de datos.\u003c/p\u003e","title":"Como conectar SpringBoot a una Base de Datos"},{"content":"Una entidad es la representación de información que nosotros necesitamos en nuestra aplicación.\nEsta entidad podría ser un usuario, un producto o cualquier dato que nuestra aplicación necesita mantener persistente para luego recuperarla cuando la necesite.\nQue es una entidad para Spring Boot #Una entidad es un objeto, elemento o \u0026lsquo;cosa\u0026rsquo; con atributos particulares que lo distinguen. Por ejemplo, este podría ser un \u0026lsquo;user (usuario)\u0026rsquo; sobre el que necesitamos conocer sus atributos como el nombre, edad, email, etc.\nComo definir una entidad en Spring Boot #Pensemos en una entidad simple. Por ejemplo, una entidad para guardar los usuarios de una aplicación.\nPresta atención a estos puntos en este ejemplo de entidad:\nDefines la entidad con la anotación @Entity Es necesario una primary key (PK) (clave primaria) con @ID El valor de esta PK es generada automáticamente con esta anotación @GeneratedValue con el valor AUTO Hay otras anotaciones que puedes utilizar.\n@Table para definir explícitamente el nombre de la tabla. @Column para definir el nombre de la columna. En caso de no usar estas anotaciones (Table, Column), Spring decidirá por convención esos nombres.\nComo usar una entidad en Spring Boot #Spring principalmente usa entidades para reconocer cuales clases representan el modelo de datos. Con esto, Spring puede realizar las acciones habituales sobre la base de datos para la entidad, como insertar, eliminar, buscar, etc.\nProbablemente el uso de las entidades es con los repositorios. Por favor, revisa este articulo a fin de entender sobre los repositorios.\nRelaciones Una a Muchas One en una entidad #Una entidad podría tener una más de una relación con otra entidad.\nSupongamos que tenemos una entidad \u0026lsquo;User\u0026rsquo; y la entidad \u0026lsquo;Task\u0026rsquo; en nuestra aplicación.\nun User puede utilizar \u0026lsquo;una o muchas (one or many)\u0026rsquo; Task\n¿Cómo definir una relación \u0026lsquo;one to many\u0026rsquo; entre dos entidades?\nEn la primera entidad tú tienes que crear una \u0026rsquo;lista de Task\u0026rsquo; y anotar esta con @OneToMany .\nUsando mappedBy indicas que la relación es unidireccional. En otras palabras, un \u0026lsquo;User\u0026rsquo; tiene muchas \u0026lsquo;Task\u0026rsquo; pero una \u0026lsquo;Task\u0026rsquo; no tiene muchos usuarios. En la segunda entidad tu tienes que crear una referencia a \u0026lsquo;User\u0026rsquo; y anotarla con @ManyToOne\n@JoinColumn refiere a la columna con la que vamos a relacionar esta table con \u0026lsquo;User\u0026rsquo;. En resumen: # @OneToMany. Define una relación one-to-many (uno a muchos). mappedBy. Indica cuál entidad es dueña del uno a muchos de forma única. @ManyToOne. Usas esto para definir la relación many-to-one (muchos a uno). @JoinColumn. Para determinar la columna que usaremos como clave para lograr la relación con la entidad principal. Conclusión #Has aprendido como crear entidades y como mapear dos entidades una con otra usando relaciones del tipo one-to-many and many-to-one.\n","date":"6 abr 2022","permalink":"https://gustavopeiretti.com/spring-boot-entities-conceptos-iniciales/","section":"Posts","summary":"\u003cp\u003eUna entidad es la representación de información que nosotros necesitamos en nuestra aplicación.\u003c/p\u003e\n\u003cp\u003eEsta entidad podría ser un usuario, un producto o cualquier dato que nuestra aplicación necesita mantener\npersistente para luego recuperarla cuando la necesite.\u003c/p\u003e","title":"Spring Boot Entities"},{"content":"En este post vamos a entender que es un componente Repository y como se crea un CrudRepository en Spring Boot.\nQue es un componente Repository #Un @Repository es un componente y a su vez un estereotipo de Spring que forma parte de la \u0026lsquo;capa de persistencia\u0026rsquo;.\nLa capa de persistencia es la forma que tiene nuestro micro-servicio para guardar y recuperar las entidades que necesita.\nUna entidad es la clase de nuestra aplicación que representa un objeto de su negocio, por ejemplo un Usuario, Cliente, Producto, etc.\nSi nuestra aplicación necesita de un User (usuario con su nombre, apellido, fecha de nacimiento) y requiere guardarlo, este User es una entidad de nuestro modelo del dominio y forma parte de la capa de persistencia.\nUn micro-servicio lo dividimos en capas, siendo el repository la capa de persistencia que tiene acceso a los datos y que puede manipularlos.\nHas una lectura de este otro artículo en donde hemos trabajado con los los Componentes y los Estereotipos en Spring Boot\n¿Cómo creamos el componente Repository? #En Spring un \u0026lsquo;Repository\u0026rsquo; es el componente encargado de resolver el acceso a los datos de nuestro micro-servicio. Si necesitamos guardar, modificar, eliminar registros de un \u0026lsquo;User\u0026rsquo; del sistema; será entonces el componente UserRepository el encargado de realizar cambios directos sobre los registros de Usuario.\nSpring nos provee las funcionalidades básicas para guardar, eliminar y buscar entidades. Para esto tenemos todas las interfaces que extienden de \u0026ldquo;org.springframework.data.repository.Repository\u0026rdquo; .\nPara nuestra entidad User podemos pensar en las operaciones básicas para crear, modificar y buscar (CRUD).\nCRUD es un acrónimo que refiere a las cuatro funciones mínimas sobre una entidad \u0026ndash;\u0026gt; Create, Read, Update, Delete.\nNuestra entidad se ve así:\n@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String surname; private LocalDate birthDate; // sets, gets... Vamos a crear una interface UserRepository que extenderá de CrudRepository.\nAnotamos la clase \u0026lsquo;UserRepository\u0026rsquo; como un componente @Repository .\nCrudRepository es una interfaz genérica que recibe dos tipos. El primero es la clase que esta interfaz manejará y el segundo es el tipo de dato del ID de la entidad.\nObserva, que NO implementamos la interfaz. Creamos una nueva interfaz y extendemos de CrudReposity. Será Spring el encargado de la implementación de la interfaz con la clase concreta.\nLos métodos que nos provee CrudRepository son:\nsave: guarda una entidad saveAll: guarda las entidades de una lista iterable findById: busca por el identificador existsById: verifica si existe un identificador findAll: devuelve todos los elementos para la entidad findAllById: busca todos los elementos que tengan el identificador count: devuelve el total de registros de la entidad deleteById: elimina un registro para el identificador delete: elimina la entidad deleteAllById: elimina todos los elementos que correspondan con el id deleteAll(Iterable): elimina todos los elementos que se reciban en el parámetro deleteAll(): elimina todos los elementos Nuestra interfaz UserRepository que extiende de CrudRepository.\nimport com.example.springbootcourse.model.User; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends CrudRepository\u0026lt;User, Long\u0026gt; { } Con esto ya tenemos creado nuestro repository con las operaciones CRUD para nuestra entidad. Las podemos utilizar desde nuestro service\nConclusión #En este artículo aprendimos qué es y creamos un Repository en SpringBoot y definimos uno CRUD utilizando la interfaz CrudRepository.\n","date":"1 dic 2021","permalink":"https://gustavopeiretti.com/spring-boot-componente-repository/","section":"Posts","summary":"\u003cp\u003eEn este post vamos a entender que es un componente Repository y como se crea un CrudRepository en Spring Boot.\u003c/p\u003e","title":"El componente Repository en Spring Boot"},{"content":"En este post vamos a entender que es un componente Service y como se crea en Spring Boot.\nQue es un componente Service #En este otro artículo aprendimos sobre los los Componentes y los Estereotipos en Spring Boot\nAlli entendimos que un @Service es un componente y un estereotipo de Spring que forma parte de \u0026rsquo;la capa de servicio'.\nUn micro-servicio lo dividimos en capas siendo el service la capa intermedia con la lógica del negocio.\nEntonces un componente \u0026lsquo;Service\u0026rsquo; es el componente encargado de resolver la lógica de negocio dentro de nuestra aplicación. Si tenemos en nuestro servicio que gestionar, por ejemplo, un \u0026lsquo;usuario\u0026rsquo; del sistema; será entonces el componente UserService el encargado de incorporar las funcionalidades en sus métodos.\n¿Cómo creamos el componente Service? #Lo que debemos hacer es pensar las operaciones que necesitamos realizar sobre nuestro User y crear los métodos para tal fin. Para este ejemplo, pensaremos en las operaciones básicas para crear, modificar y buscar que denominamos CRUD.\nCRUD es un acrónimo que refiere a las cuatro funciones mínimas sobre una entidad \u0026ndash;\u0026gt; Create, Read, Update, Delete.\nAnotamos la clase \u0026lsquo;UserService\u0026rsquo; como @Service\n@Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public User create(User user) { return userRepository.save(user); } public User update(User user) { return userRepository.save(user); } public User change(User user) { return userRepository.save(user); } public boolean remove(long id) { if (userRepository.existsById(id)) { userRepository.deleteById(id); return true; } else { return false; } } public Optional\u0026lt;User\u0026gt; find(long id) { return userRepository.findById(id); } } Vemos nuestro service delega en otro componente, el Repository, el acceso directo a los datos. El detalle de este repository lo vemos en otro artículo.\nDesde un controlador que creamos llamamos a las funcionalidades del servicio.\nPara esto, levantamos nuestra aplicación. Lee este artículo donde explico como crear el main de una aplicacion en Spring Boot e iniciarlo.\ngradlew booRun @RestController public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping(\u0026#34;/api/user/{id}\u0026#34;) public User byId(@PathVariable(\u0026#34;id\u0026#34;) int id) { return userService.find(id).orElseThrow(); } @PostMapping(\u0026#34;/api/user/\u0026#34;) public User create(@RequestBody User user) { return userService.create(user); } @PutMapping(\u0026#34;/api/user/\u0026#34;) public User update(@RequestBody User user) { return userService.update(user); } @PatchMapping(\u0026#34;/api/user/\u0026#34;) public User change(@RequestBody User user) { return userService.change(user); } @DeleteMapping(\u0026#34;/api/user/{id}\u0026#34;) public boolean delete(@PathVariable(\u0026#34;id\u0026#34;) int id) { return userService.remove(id); } } Creamos, buscamos y eliminamos un usuario desde el controller que llama al service.\nConclusión #En este artículo aprendimos a crear un Service en SpringBoot y entendimos el proposito que tiene el componente @Service en una aplicación Rest.\n","date":"26 nov 2021","permalink":"https://gustavopeiretti.com/spring-boot-componente-service/","section":"Posts","summary":"\u003cp\u003eEn este post vamos a entender que es un componente Service y como se crea en Spring Boot.\u003c/p\u003e","title":"El componente Service en Spring Boot"},{"content":"Para crear un proyecto en Spring Boot podemos utilizar el asistente de IntelliJ.\nCrear un proyecto SpringBoot con IntelliJ #Esta opción es para IntelliJ Ultimate. Si no tienes IntelliJ Ultimate puedes usar Spring Initializr Tenemos otra forma de crear proyectos fácilmente utilizando Intellij\nCon IntelliJ tenemos diferentes opciones:\nElegir si usaremos Maven o Gradle para la construcción de nuestro proyecto. Las versiones de Spring y Java que usaremos. Los datos del tu proyecto para el grupo y el artefacto. Las dependencias que necesitas. Desde la línea de comandos podemos arrancar la aplicación.\ngradlew bootRun También podemos utilizar IntelliJ para iniciar la aplicación. Para esto abrimos la clase main de Spring Boot y desde el main iniciamos nuestra aplicación.\nConclusión #IntelliJ dispone de las herramientas para simplificar la creación inicial y dependencias de tu proyecto en Spring Boot.\n","date":"24 nov 2021","permalink":"https://gustavopeiretti.com/crear-proyecto-spring-boot-intellij/","section":"Posts","summary":"\u003cp\u003ePara crear un proyecto en Spring Boot podemos utilizar el asistente de IntelliJ.\u003c/p\u003e","title":"Como crear un Proyecto de Spring Boot con Intellij"},{"content":"Para crear un proyecto en Spring Boot podemos acceder a la utilidad \u0026lsquo;Spring Initializr\u0026rsquo; .\nSpring Initializr #Spring Initializr es una herramienta de Spring que nos ayuda a crear un proyecto inicial, desde cero, eligiendo de forma simple las dependencias que necesitamos. Abrimos el sitio Spring Initializr\nAllí contamos con multiples opciones:\nElegir si usaremos Maven o Gradle para la construcción de nuestro proyecto. Las versiones de Spring y Java que usaremos. Los datos del tu proyecto para el grupo y el artefacto. Las dependencias que necesitas. Para nuestro proyecto elegiremos Gradle y la dependencia Spring Web Una vez elegidas las opciones puedes explorar para previsualizar cómo quedará tu archivo build.gradle y tu proyecto. En la opción GENERATE descargas el file .zip del proyecto listo para utilizar.\nUna vez descargado el archivo lo descomprimimos.\nLo abrimos con nuestro IDE de preferencia, en mi caso Intellij\nDesde la línea de comandos podemos ya ejecutar la aplicación.\ngradlew bootRun Conclusión #Spring Initializr es una herramienta que simplifica la creación inicial y dependencias de tu proyecto.\nReferencias #Spring Initializr GitHub\n","date":"15 nov 2021","permalink":"https://gustavopeiretti.com/crear-proyecto-spring-boot-initilizr/","section":"Posts","summary":"\u003cp\u003ePara crear un proyecto en Spring Boot podemos acceder a la utilidad \u0026lsquo;Spring Initializr\u0026rsquo; .\u003c/p\u003e","title":"Como crear un Proyecto de Spring Boot con Spring Initilizr"},{"content":"Spring Boot maneja un archivo de propiedades para llevar allí las configuraciones generales de la aplicación.\nDonde se ubica el archivo de propiedades application.properties #El archivo de propiedades se ubica en la carpeta src/main/resources de nuestra aplicación. Este archivo nos permite configurar Spring y definir configuraciones propias para nuestra aplicación.\nHay una gran cantidad de propiedades que se pueden establecer, podemos ver una lista aquí. Observa, que existen dieciséis categorías que clasifican a las propiedades, que van desde el \u0026lsquo;core\u0026rsquo; de Sprint, pasando por configuraciones de datos hasta testing.\nUn ejemplo de nuestro archivo de propiedades podría verse así:\nEn este archivo application.properties estamos usando las propiedades ya definidas por Spring para darle un nombre a nuestra aplicación, cambiar el puerto en el cual corre e indicarle configuraciones sobre base de datos.\nEl uso de un archivo de propiedades en formato YAML #YAML es un formato de sintaxis que también sirve para almacenar propiedades en un formato jerárquico.\nPor ejemplo, si llevamos las propiedades anteriores a un formato YAML quedaría de este modo nuestro archivo application.yml:\nConclusión #Un archivo de propiedades en Spring Boot nos permite configurar aspectos de la aplicación y establecerle parámetros propios. Tenemos dos formatos de propiedades, los .properties planos y los .yml que dan un formato jerárquico.\n","date":"10 nov 2021","permalink":"https://gustavopeiretti.com/archivo-propiedades-spring-boot/","section":"Posts","summary":"\u003cp\u003eSpring Boot maneja un archivo de propiedades para llevar allí las configuraciones generales de la aplicación.\u003c/p\u003e","title":"El archivo de Propiedades en Spring Boot"},{"content":"En una aplicación desarrollada en Spring Boot debemos tener cuidado en ordenar y estructurar los paquetes de modo que quede claro su propósito. Veremos la forma más estandarizada para ordenar los paquetes en Spring Boot.\n¿Cómo debemos ordenar los paquetes en una aplicación Spring Boot? #Noy hay una forma obligatoria que Spring nos imponga para el nombrado y la estructura de nuestros paquetes. Sin embargo, sí existen recomendaciones, usos comunes y buenas prácticas.\nUna buena recomendación y buena práctica es dividir nuestro proyecto en capas. Podemos dividir nuestro proyecto en un paquete para los controladores, otro para los servicios, el modelo de nuestros datos y el acceso a la base de datos.\nEn otro artículo vimos los componentes y estereotipos en dónde ya Spring nos propone una división en Controller, Service, Repository a fin de ordenar mejor nuestro código.\nAprovechando esto podemos crear los paquetes para cada estereotipo de este modo.\nPaquete controller para todos los endpoints que tenga nuestra aplicación. Paquete service para agregar alli las clases que respondan a la funcionalidad y lógica. Paquete model para las representaciones de nuestro modelo de datos (entidades). Paquete repository para las clases que establecen la comunicación con la base de datos. Nuestro proyecto se vería de este modo.\nAdemás de estos paquetes para nuestras clases vemos otras carpetas para los resources, y el paquete para los test. En la carpeta resources ubicamos el archivo de propiedades.\nConclusión #Vimos aquí la distribución habitual y clásica en el ordenamiento de paquetes. Sin embargo, dividir paquetes en capas es la más utilizada y que deberías tener presente.\n","date":"1 nov 2021","permalink":"https://gustavopeiretti.com/estructura-de-paquetes-spring-boot/","section":"Posts","summary":"\u003cp\u003eEn una aplicación desarrollada en Spring Boot debemos tener cuidado en ordenar y estructurar los paquetes de modo que quede claro su propósito.\nVeremos la forma más estandarizada para ordenar los paquetes en Spring Boot.\u003c/p\u003e","title":"Estructura de Paquetes en una aplicación de Spring Boot"},{"content":"Vamos a entender el concepto de componentes dentro de una aplicación en Spring Boot y el uso de los estereotipos.\nQue es un componente (@Component) #Un component es lo que le permite a Spring detectar los beans y colocarlos dentro de su contexto para ser utilizados. Aprendimos antes, algunos conceptos sobre lo que es inyección de dependencias en Spring. Allí entendimos el concepto de un bean y vimos que los bean son objetos administrados por Spring.\nCuando indicamos que una clase es un @Component, lo que hacemos es decirle a Spring que queremos que cree una instancia y la gestione.\n@Component public class MyClass { public void doSomething() { //.. } } Al momento de inicializar la aplicación, Spring hará lo siguiente:\nBuscará dentro de la aplicación las clases anotadas con @Component Creará una instancia de los componentes Dejará el componente en su contexto Buscará quién necesita esos componentes y los inyectará en quién los necesite. Que son los estereotipos #Los estereotipos (Stereotypes) son componentes que extienden de @Component.\nLos estereotipos más comunes son:\n@Controller / @RestController @Service @Repository Todos ellos son también @Component, pero orientados a formar parte en una \u0026lsquo;capa\u0026rsquo; particular de nuestro servicio.\nUn @Controller formará parte de la \u0026lsquo;capa\u0026rsquo; de controladores de Spring.\nUn @Service será parte de la \u0026lsquo;capa\u0026rsquo; de servicios encargado de la funcionalidad del negocio.\nUn @Repository será parte de la \u0026lsquo;capa\u0026rsquo; de persistencia cuya función será el acceso a los datos.\nObserva, por ejemplo, la anotación @Service que es en definitiva un alias de un @Component. Lo mismo sucede con el resto de estereotipos.\nComo utilizar los componentes @Controller, @Service, @Repository #Recordemos que un rest controller es también un controller. Tenemos varias formas para utilizar los componentes en nuestras clases.\nReferencia por constructor: #Una vez que hemos creado los componentes, tenemos varias formas requerirlos.\nUna de ellas y la recomendada es mediante el constructor.\nSpring al crear la instancia reconocerá que esta clase necesita en su constructor otro componente y se encargará de construir la clase utilizando el componente que necesite.\nObserva que no es necesario el uso de @Autowired en este caso.\nReferencia por atributo con @Autowired: #También podemos referenciar una dependencia mediante el uso de los atributos utilizando la annotation @Autowired\nAutowired cargará el atributo con el componente utilizando reflection.\nReferencia por setter con @Autowired: #Además de la referencia por constructor y por atributos, es posible agregar referencias en un los métodos set.\nConclusión #En este artículo aprendimos qué es y como usamos un Component en Spring y sus estereotipos @Controller, @Service, @Repository para crear una aplicación Rest en Spring Boot.\nVisita este artículo sobre el Service y el Repository.\n","date":"22 oct 2021","permalink":"https://gustavopeiretti.com/spring-boot-componentes-estereotipos/","section":"Posts","summary":"\u003cp\u003eVamos a entender el concepto de componentes dentro de una aplicación en Spring Boot y el uso de los estereotipos.\u003c/p\u003e","title":"Que son los Componentes y los Estereotipos en Spring Boot"},{"content":"En este post vamos a entender que es un controlador y como se crea un controlador en Spring Boot.\nQue es un controlador Rest Controller #Un controller es un componente de Spring capaz de recibir peticiones http y responderlas.\nLas clases que definimos como un controller es responsable de procesar las llamadas entrantes (request) que ingresan a nuestra aplicacion, validarlas y dar una respuesta (response).\nUn rest controller es un tipo de controller que reciben peticiones con un formato de específico que cumple con formatos de solicitud RESTful habitualmente y mayormente en JSON , aunque a veces se usan otros como HTML, XML, o simplemente texto.\nComo crear un RestController con Spring Boot #El primer paso para crear un \u0026lsquo;controlador rest\u0026rsquo; es anotar la clase que con @RestController.\nCon esto Spring ya sabe que esa clase será un componente encargado de recibir llamadas.\n@RestController public class HelloWordController { } Una vez que hemos anotado la clase podemos definir el método y la ruta en la cual recibirá la llamada externa.\nAnotamos el método que da respuesta con @GetMapping y le indicamos la ruta en la cual responderá . Aquí definimos el path \u0026ldquo;/hello\u0026rdquo;.\n@RestController public class HelloWordController { @GetMapping(\u0026#34;/hello\u0026#34;) public String sayHello() { return \u0026#34;Hello dev\u0026#34;; } } Arrancamos la aplicación.\ngradlew booRun Puedes leer este artículo donde explico el main de Spring Boot y como iniciarlo\nAhora podemos invocar nuestro RestControler mediante una llamada en el path \u0026lsquo;/hello\u0026rsquo; que definimos previamente.\nEl servicio levanta en \u0026rsquo;localhost:8080\u0026rsquo; y el path es \u0026lsquo;/hello\u0026rsquo;. Vemos la respuesta \u0026lsquo;Hello dev\u0026rsquo;\nTipos de mapeos en un rest controller de Spring Boot #En el punto anterior creamos un mapping para el path \u0026lsquo;/hello\u0026rsquo; . Este mapeo lo definimos como un @GetMapping.\nSin embargo, debemos saber que hay otros tipos de mapping en Spring Boot.\nEn los métodos de un mapeo podemos usar:\nGet: para solicitar información de un recurso. Post: para enviar información a fin de crear o de actualizar un recurso. Put: para enviar información a fin de modificar un recurso. Patch: actualiza una parte del recurso. Delete: elimina un recurso específico. ¿Cuál es la diferencia entre Post , Put, Patch?\nHabitualmente la diferencia entre Post y Put radica en que Post lo usamos para añadir un recurso y Put lo utilizamos para modificar un recurso en particular.\nPatch también lo utilizamos para actualizar un recurso pero solo una parcialidad del mismo.\nEjemplos de mapeo en Spring Boot #A continuación vemos ejemplos simples de mapeo.\nPara el caso del GetMapping estamos pidiendo mediante un id al recurso User. A fin de recibir este id utilizamos PathVariable\nPara el PostMapping, PutMapping, PatchMapping se recibe un request con el body del User que se quiere insertar o actualizar.\nEl uso de RequestBody permite que Spring entienda la info que mandamos body de la petición.\nEn el DeleteMapping recibimos también id que identifica el objeto a eliminar y se devuelve true / false según si se pudo eliminar o no.\n@RestController public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping(\u0026#34;/api/user/{id}\u0026#34;) public User byId(@PathVariable(\u0026#34;id\u0026#34;) int id) { return userService.find(id); } @PostMapping(\u0026#34;/api/user/\u0026#34;) public User create(@RequestBody User user) { return userService.create(user); } @PutMapping(\u0026#34;/api/user/\u0026#34;) public User update(@RequestBody User user) { return userService.update(user); } @PatchMapping(\u0026#34;/api/user/\u0026#34;) public User change(@RequestBody User user) { return userService.change(user); } @DeleteMapping(\u0026#34;/api/user/{id}\u0026#34;) public boolean delete(@PathVariable(\u0026#34;id\u0026#34;) int id) { return userService.remove(id); } } ¿Cómo haríamos la llamada a cada ruta? #Observa las llamadas que hacemos usando el cliente https://www.postman.com/\nGetMapping para la ruta /api/user/{id} con el id a buscar\nPostMapping para la ruta /api/user/ enviando el body con los datos\nPutMapping para la ruta /api/user/ enviando el body con los datos\nPatchMapping para la ruta /api/user/ enviando el body con los datos\nDeleteMapping para la ruta /api/user/{id} con el id a eliminar\nConclusión #En este artículo aprendimos a crear un Rest Controller en SpringBoot con un \u0026lsquo;path\u0026rsquo; definido por nosotros y como invocarlo.\nAprendimos el uso de las anotaciones necesarias para crear un controlador en Spring utilizando RestController , GetMapping, PostMapping, PutMapping, PatchMapping, DeleteMapping.\n","date":"21 oct 2021","permalink":"https://gustavopeiretti.com/spring-boot-crear-controlador/","section":"Posts","summary":"\u003cp\u003eEn este post vamos a entender que es un controlador y como se crea un controlador en Spring Boot.\u003c/p\u003e","title":"Como crear un controlador Rest en Spring Boot"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/rest-api/","section":"Tags","summary":"","title":"REST API"},{"content":"Para crear una aplicación web en Spring Boot necesitamos primero determinar las librerías mínimas y luego crear el main java de la aplicación para arrancar el servicio. Veremos aquí como crear el main de Spring Boot para que se inicie.\nLa dependencia mínima que necesita Spring Boot para arrancar #Para esta aplicación usaremos la dependencia spring-boot-starter-web que nos provee todo el paquete de librerías para una aplicación que de respuestas ante peticiones web.\ndependencies{ implementation \u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; } En este otro post hablamos sobre estas dependencias started y su utilidad para la construir nuestros servicios.\nEl main de Spring Boot y su anotación #Para iniciar nuestra aplicación lo primero que necesitamos es crear una clase con el metodo main . Anotamos la clase con SpringBootApplication y le damos la instruccion a Spring que arranque con SpringApplication.run(\u0026hellip;) .\n¿Qué hace la anotación SpringBootApplication? #Si nos metemos dentro de la anotación SpringBootApplication podemos observar que esta anotación de arranque es la suma de las anotaciones SpringBootConfiguration, EnableAutoConfiguration, ComponentScan\n@SpringBootConfiguration: indica que una clase proporciona la configuración de la aplicación. Es un alias de @Configuration con la diferencia en que SpringBootConfiguration permite que Spring encuentre las configuraciones automáticamente.\n@EnableAutoConfiguration: permite que Spring Boot configure automáticamente la aplicación y registre los beans para su utilización. Esta autoconfiguración se aplica basada en las dependencias de la aplicación. La autoconfiguración intenta evitar configuraciones tediosas usando la inteligencia de Spring para tomar decisiones en cuando a las configuraciones habituales.\n@ComponentScan: le da la directiva a Spring para que haga una búsqueda de todos los componentes anotados dentro de los paquetes. Es decir, buscará todo lo que esté anotado como @Component y sus clases hijas (Service, Repository, Controller) registrándolas en su contexto.\nResumiendo hasta aquí, la anotación @SpringBootApplication le da la instrucción a Spring Boot para buscar @Beans de config, además activa la autoconfiguración dejando que Spring tome decisiones en cuanto a las configuraciones por default y realiza un escaneo de componentes en la aplicación.\nComo iniciar la aplicación con SpringBootApplication #Una vez que ya tenemos el main de la aplicación anotada con @SpringBootApplication y con la instrucción SpringApplication.run(\u0026hellip;) , ya esta lista para iniciarse.\nNuestra aplicación se ve de este modo.\nUtilizamos aquí Gradle como gestor de dependencias y de construcción de la aplicación.\nbuild.gradle\nplugins { id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.5.4\u0026#39; id \u0026#39;io.spring.dependency-management\u0026#39; version \u0026#39;1.0.11.RELEASE\u0026#39; id \u0026#39;java\u0026#39; } group = \u0026#39;com.example\u0026#39; version = \u0026#39;0.0.1-SNAPSHOT\u0026#39; sourceCompatibility = \u0026#39;11\u0026#39; repositories { mavenCentral() } dependencies { implementation \u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; } test { useJUnitPlatform() } ¿Qué comando se utiliza para arrancar Spring Boot? #La instrucción para iniciar nuestra aplicación Spring Boot desde la línea de comandos es gradlew booRun .\nUbicados en el path donde tenemos nuestra aplicación ejecutamos gradlew booRun\ngradlew booRun En linux ./gradlew booRun\nEn Windows gradlew booRun\nConclusión #El main de Spring Boot es bastante simple, con unas pocas líneas y dependencias podemos crear e iniciar nuestra aplicación en Spring Boot.\nLa anotación SpringBootApplication la utilizamos para que Spring configure la aplicación y busque los componentes que necesitamos. Para iniciar la aplicacion usamos gradlew booRun con gradle .\n","date":"13 oct 2021","permalink":"https://gustavopeiretti.com/spring-boot-main-class/","section":"Posts","summary":"\u003cp\u003ePara crear una aplicación web en Spring Boot necesitamos primero determinar las librerías mínimas y luego crear el \u003cem\u003emain java\u003c/em\u003e de la aplicación para arrancar el servicio.\nVeremos aquí como crear el main de Spring Boot para que se inicie.\u003c/p\u003e","title":"Como crear el main class en Spring Boot"},{"content":"La inyección de dependencias es un patrón de diseño que tiene como objetivo tomar la responsabilidad de crear las instancias de las clases que otro objeto necesita y suministrárselo para que esta clase los pueda utilizar.\n¿Qué es la inyección de dependencias entre clases? #Habitualmente nuestras clases dependen de otras para funcionar.\nPor ejemplo, una clase que necesita buscar un registro en la base de datos necesitará de otra que se encargue de buscarlo.\nPensemos en estas dos clases. Llamemos a la primera CassA que es la cargada de tomar decisiones sobre el negocio y a la segunda ClassB, la cual se encargará de acceder a la base de datos.\nEn la inyección de dependencias \u0026lsquo;alguien\u0026rsquo; externo se encarga de las dependencias que las clases necesitan\u0026hellip;\nLa clase ClassA depende de la clase ClassB para lograr el acceso a los datos en la base de datos.\nAquí \u0026rsquo;normalmente\u0026rsquo; en la la ClassA creariamos la ClassB . La ClassA sería la responsable de crear a la ClassB.\nLa Inversión de control en Spring #Spring maneja el concepto de IoC (Inversion of Control) ocupándose de mantener en su \u0026lsquo;contexto\u0026rsquo; todas las instancias de nuestra aplicación y de inyectarle esa instancia a quien la necesite.\nSpring llama a estas instancias beans .\nLos bean son las instancias de las clases que están disponibles para ser reutilizados y son gestionados dentro del contenedor de Spring.\nIoC es el trabajo que realiza Spring buscando estas dependencias entre los objetos y realizando el \u0026lsquo;set\u0026rsquo; estos beans en quien los requiera.\nSpring sabe qué dependencias existen entre las instancias y se encarga de satisfacerlas.\nBusca en su contenedor de beans la instancia adecuada y se la agrega al objeto cumpliendo así con la inyección de dependencias.\nComo realizamos la inyección de dependencias con Spring #Spring nos da diferentes modos para inyectar las dependencias.\nLa más común y más recomendada es mediante el uso de anotaciones.\nLa anotación general para indicar que queremos que una clase sea gestionada por el contenedor de Spring es @Component .\nAl anotar nuestra clase con @Component le decimos a Spring que deseamos que esa clase sea un bean .\nPor lo tanto será Spring el que hará un new de la clase y creará la instancia.\n@Component public class ClassB { public void doSomething() { System.out.println(\u0026#34;working\u0026#34;); } } Nuestra clase ClassA necesita a la ClassB .\nSpring se da cuenta de esta dependencia porque nuestra clase es un componente que a su vez tiene en su constructor a la ClassB .\nSerá Spring el que cree la ClassB y luego al instanciar la ClassA le pase en el parámetro del constructor esa dependencia\n@Component public class ClassA { private final ClassB classB; public ClassA(ClassB classB) { this.classB = classB; } public void doSomething() { System.out.println(\u0026#34;working\u0026#34;); classB.doAnotherJob(); } } Cuáles son las ventajas de la Inyección de dependencias #Mayor cohesión y menor acoplamiento:\nSiempre que construimos una aplicación debemos pensar en reducir el acoplamiento entre las clases y aumentar la cohesión.\nEsto significa que cada clase debe tener una única responsabilidad, debe ser bien específica en dicha responsabilidad y hacerla bien (cohesión).\nPor la reducción del acoplamiento refiere a que los cambios en una clase no deberían impactar en otra.\nAl crear nuestras clases sabiendo que Spring será el encargado de crearlas y de inyectarlas, nos libera para enfocarnos solamente en la funcionalidad de nuestra clase en construcción.\nCreamos nuestra clase y definimos sus responsabilidades pensando solo en el ámbito de esa clase. Establecemos cuáles serán los métodos de esa clase para que puedan ser utilizados por otras, pero sin estar pendientes de otras clases.\nReutilización:\nUna clase está pensada en ser reutilizable por quien la necesite.\nUna clase responsable del acceso a la base puede ser utilizada por otras a través del contrato definido en sus métodos y ser inyectada en todas aquellas que necesiten el acceso a la base de datos.\nCambios de arquitectura:\nAl diseñar las clases pensando en su interfaz. Podemos realizar cambios internos mientras mantengamos el contrato de la clase sin afectar a otras que la están usando.\nPruebas:\nLas pruebas unitarias sobre las clases es mucho más simple, pudiéndose utilizar mocks para aquellas que no son del ámbito de la prueba puntual.\nConclusión #Entendimos el concepto de dependencia y de IoC y como Spring nos ayuda con la gestión de todas las dependencias entre clases dentro de nuestra aplicación. Vimos que utilizando Spring podemos ocuparnos de crear nuestras clases pensando solo en su lógica y dejando la tarea de las dependencias en Spring. Entendimos la utilidad de IoC y sus ventajas.\n","date":"12 oct 2021","permalink":"https://gustavopeiretti.com/spring-inyeccion-dependencias/","section":"Posts","summary":"\u003cp\u003eLa inyección de dependencias es un patrón de diseño que tiene como objetivo tomar la responsabilidad de crear las instancias de las clases que otro objeto necesita y suministrárselo para que esta clase los pueda utilizar.\u003c/p\u003e","title":"Que es la inyección de dependencias en Spring"},{"content":"Spring Boot es un conjunto de componentes que te proveen las herramientas para crear servicios rápidamente y con un mínimo esfuerzo.\nUtiliza configuraciones preestablecidas que te ahorran tiempo y repeticiones en el desarrollo de aplicaciones.\nAdemás pone a tu disposición las librerías para la mayoría de las necesidades en la creación de servicios, micro servicios y aplicaciones Rest.\nSumado a esto te ordena la arquitectura de tu código dándote las bases iniciales para cada proyecto.\nSpring Boot es parte de un conjunto de proyectos que forman parte del ecosistema de soluciones de Spring. Cada proyecto de Spring resuelve un problema en particular.\nEn este caso Spring Boot resuelve la creación de aplicaciones orientadas a producción, de ejecución rápida y escalable. Se integra de forma sencilla con otros proyectos de Spring como Spring Data, Spring Cloud, Spring Security, mediante interfaces comprensibles.\nPuedes pegarle un vistazo en la página de Spring a los proyectos de Spring. Entre ellos vemos Spring Boot.\nCuáles son las características principales de Spring Boot: # Es liviano y con una arquitectura simple enfocada en la inyección de dependencias. Te entrega las dependencias iniciales agrupadas y listas para su uso. Configuraciones preestablecidas y automáticas que te ahorran esfuerzo en configuraciones repetitivas o engorrosas. Acceso a librerías de terceros mediante interfaces para su uso. Integrar Tomcat, Jetty o Undertow sin necesidad de estar desplegando archivos en los contenedores de aplicaciones. Fácil de testear y con herramientas para el testing. Simplifica notablemente la persistencia de datos y consultas sobre los datos. Monitoreo de nuestra aplicación. Está preparado para su funcionamiento en Cloud Spring Boot trabaja con Inyección de dependencias (IoC): #Spring utiliza este patrón denominado Inversion of Control (IoC). La inversión de control e inyección es uno de los aspectos principales de Spring Framework.\nSpring Boot siendo una capa por encima de Spring Framework obviamente utiliza este patrón para agregar a las partes de nuestro código las diferentes responsabilidades que necesita.\nEste patrón refiere a que a una clase en particular se le suministran las subsecuentes clases que la primera necesita inyectándoselas para que las use.\nSpring es el que maneja estas dependencias suministrándoselas a quien las necesite.\nSpring Boot dispone de dependencias inicializadoras o Started: #Las dependencias inicializadoras \u0026ldquo;started\u0026rdquo; de Spring Boot te proveen el conjunto de dependencias ya agrupadas y listas para su uso.\nTodos los inicializadores \u0026ldquo;started\u0026rdquo; tienen la nomenclatura *spring-boot-starter- **\nPor ejemplo el paquete de dependencias spring-boot-starter-web nos da las librerías para arrancar una aplicación web en un Tomcat, crear un controlador que reciba una petición y responder.\nOtro ejemplo de un \u0026ldquo;started\u0026rdquo; es spring-boot-starter-data-jpa que nos da acceso a los datos de una Base de Datos.\nSpring Boot entiende como usar estos \u0026ldquo;started\u0026rdquo; y crea su autoconfiguración por default.\nSpring Boot tiene un Servidor embebido: #Spring Boot también nos ayuda a los desarrolladores a crear aplicaciones que se ejecutan sin necesidad de pensar en el servidor de aplicaciones. Esto debido a que ya incluye el servidor de aplicaciones en su ejecución.\nLo podemos ver como la posibilidad de crear aplicaciones \u0026ldquo;auto ejecutables\u0026rdquo; con un solo comando.\nSpring Boot tiene Autoconfiguraciones: #Spring Boot nos proporciona configuraciones por default para nuestra aplicación. Lo que nos da tiempo para concentrarnos en resolver la funcionalidad desde el principio sin estar repitiendo configuraciones una y otra vez.\nDe este modo tu aplicación en Spring Boot decide la mejor configuración basándose en las dependencias que estes utilizando. Por ejemplo, si tienen una dependencia de alguna base de datos como MySQL o PostgreSql, Spring decidirá la configuración apropiada para ello. Si deseas agregar o modificar alguna configuración de forma personalizada, puedes hacerlo fácilmente modificando propiedades.\nSpring Boot proporciona logs y monitoreo: #De forma standard Spring te da deja todo listo para registrar logs en tu aplicación y dejar registros que te ayudan a monitorear el estado y errores.\nQue tipo de aplicaciones podemos desarrollar en Spring Boot #Con Spring Boot podemos crear micro-servicios empresariales que brinden el soporte a funcionalidades del negocio y provean el backend para aplicaciones web, móviles y procesamiento de datos contra base de datos. Aplicaciones pequeñas y grandes en entornos en la nube escalables.\nConclusión #Spring Boot es un marco de trabajo de Java que se utiliza para crear aplicaciones web de manera más fácil y rápida. Spring Boot incluye:\nConfiguración automática: Spring Boot se encarga de gran parte de la configuración y la integración de diferentes componentes, lo que ahorra tiempo y esfuerzo. Fácil de usar: Spring Boot proporciona una gran cantidad de funcionalidades out-of-the-box, lo que permite que los desarrolladores se enfoquen en la escritura de código de negocios en lugar de en la configuración. Escalabilidad: Spring Boot está diseñado para ser escalable, lo que significa que es fácil de mantener y ampliar a medida que crece la aplicación. Integración con otros marcos: Spring Boot tiene una amplia integración con otros marcos de Java, lo que permite una fácil integración de diferentes herramientas y tecnologías. ","date":"8 sept 2021","permalink":"https://gustavopeiretti.com/spring-boot-que-es/","section":"Posts","summary":"\u003cp\u003eSpring Boot es un conjunto de componentes que te proveen las herramientas para crear servicios rápidamente y con un mínimo esfuerzo.\u003cbr\u003e\nUtiliza configuraciones preestablecidas que te ahorran tiempo y repeticiones en el desarrollo de aplicaciones.\u003cbr\u003e\nAdemás pone a tu disposición las librerías para la mayoría de las necesidades en la creación de servicios, micro servicios y aplicaciones Rest.\u003c/p\u003e","title":"Que es Spring Boot"},{"content":"Veamos en este post como implementar y configurar Apache Kafka con SpringBoot. Spring provee una forma simple de integrarse con Kafka para enviar mensajes. Mediante anotaciones podemos recibir los mensajes de Kafka y a través del uso de un template enviamos fácilmente los mensajes.\nKafka nos da la infraestructura para enviar mensajes utilizando producers y consumers que los receptan. Los mensajes que se producen y se consumen se envían a través de topics. Un tópico es la categoría del mensaje que se está enviando.\nDependencias para Kafka en Spring Boot #Necesitaremos las siguientes dependencias para nuestro proyecto\n\u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; \u0026#39;org.springframework.kafka:spring-kafka\u0026#39; \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; \u0026#39;org.springframework.kafka:spring-kafka-test\u0026#39; Proyecto de Spring Boot con Kafka #Crearemos nuestro proyecto de Spring Boot igual que cualquier otro.\n@SpringBootApplication public class DemoKafkaApplication { public static void main(String[] args) { SpringApplication.run(DemoKafkaApplication.class, args); } } Definiendo nuestro KafkaTemplate para enviar mensajes a un tópico de Kafka #Para enviar mensajes debemos definir KafkaTemplate.\nLo primero que debemos saber es qué tipo de mensajes queremos enviar.\nHabitualmente el key es un String y el tipo de dato varía entre String u Objetos. Aquí, definimos mensajes de tipo String para el valor.\nKafkaTemplate\u0026lt;String, String\u0026gt; kafkaTemplate; @Configuration public class KafkaStringConfig { public ProducerFactory\u0026lt;String, String\u0026gt; producerFactory() { Map\u0026lt;String, Object\u0026gt; config = new HashMap\u0026lt;\u0026gt;(); config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, \u0026#34;127.0.0.1:9092\u0026#34;); config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); return new DefaultKafkaProducerFactory\u0026lt;\u0026gt;(config); } @Bean(name = \u0026#34;kafkaStringTemplate\u0026#34;) public KafkaTemplate\u0026lt;String, String\u0026gt; kafkaTemplate() { return new KafkaTemplate\u0026lt;\u0026gt;(producerFactory()); } } Definiendo un producer para enviar mensajes a un tópico de Kafka #Definiremos un productor que se encargara de producir un mensaje hacia un tópico de Kafka.\nComo vimos antes en la configuración del productor, definimos un KafkaTemplate que podemos usar en nuestros servicios o componentes.\nSolo tenemos que enviar el mensaje usando kafkaTemplate.send(..)\nkafkaTemplate.send(\u0026#34;topic\u0026#34;, \u0026#34;message\u0026#34;) Mira que en este componente estamos usando el template que creamos en la config .\n@Component public class KafkaStringProducer { private static final Logger LOGGER = LoggerFactory.getLogger(KafkaStringProducer.class); private final KafkaTemplate\u0026lt;String, String\u0026gt; kafkaTemplate; public KafkaStringProducer(@Qualifier(\u0026#34;kafkaStringTemplate\u0026#34;) KafkaTemplate\u0026lt;String, String\u0026gt; kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } public void sendMessage(String message) { LOGGER.info(\u0026#34;Producing message {}\u0026#34;, message); this.kafkaTemplate.send(\u0026#34;TOPIC-DEMO\u0026#34;, message); } } Definiendo un consumer para recibir los mensajes de un tópico de Kafka #En este ejemplo crearemos también un consumer para recibir el mensaje de Kafka. Esto habitualmente estaría en otro microservicio, pero lo haremos aquí mismo a fin de simplificar el ejemplo.\nEn el consumer anotamos el método que queremos \u0026ldquo;escuche\u0026rdquo; el mensaje. Indicando el tópico que debe escuchar.\n@KafkaListener(topics = \u0026#34;TOPIC-DEMO\u0026#34; , groupId = \u0026#34;group_id\u0026#34;) @Component public class KafkaStringConsumer { Logger logger = LoggerFactory.getLogger(KafkaStringConsumer.class); @KafkaListener(topics = \u0026#34;TOPIC-DEMO\u0026#34; , groupId = \u0026#34;group_id\u0026#34;) public void consume(String message) { logger.info(\u0026#34;Consuming Message {}\u0026#34;, message); } } Crearemos un CommandLineRunner para realizar nuestra prueba #A efectos de visualizar el funcionamiento de nuestra aplicación crearemos un CommandLineRunner que enviará mensajes cada dos segundos en un loop.\n@Component public class CommandLineAppStartupRunner implements CommandLineRunner { private final KafkaStringProducer stringProducer; public CommandLineAppStartupRunner(KafkaStringProducer stringProducer) { this.stringProducer = stringProducer; } @Override public void run(String... args) throws Exception { for (int i = 0; i \u0026lt; 10; i++) { stringProducer.sendMessage(\u0026#34;Hello kafka !! \u0026#34; + i); Thread.sleep(2000); } } } Creamos un docker compose con Kafka #Para nuestro proyecto necesitamos Kafka funcionando. Asi que usaremos un contenedor docker con Kafka.\nUsaremos una imagen de Kafka desde esta ruta de Docker Hub\nversion: \u0026#39;3\u0026#39; services: zookeeper: container_name: zookeeper_merge image: wurstmeister/zookeeper ports: - \u0026#34;2181:2181\u0026#34; networks: - kafka_merge_net kafka: container_name: kafka_merge image: wurstmeister/kafka depends_on: - zookeeper ports: - \u0026#34;9092:9092\u0026#34; environment: KAFKA_ADVERTISED_HOST_NAME: localhost KAFKA_ADVERTISED_PORT: 9092 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 ZK_SERVER: zookeeper:2181 ADVERTISED_HOST: localhost CONSUMER_THREADS: 5 BROKER_ID: 1 ADVERTISED_PORT: 9092 volumes: - /var/run/docker.sock:/var/run/docker.sock networks: - kafka_merge_net networks: kafka_merge_net: driver: bridge Iniciamos Kafka desde la imagen de docker #Debemos guardar el file docker-compose.yml y luego ejecutar en la misma ubicación\ndocker-compose up Una vez iniciado nuestro docker con Kafka podemos realizar la prueba de nuestro servicio. Vemos la ejecución del loop que definimos previamente cada dos segundos.\nArrancamos nuestro proyecto en Spring Boot #Para este ejemplo uso gradle, por lo que lo inicio gradlew bootRun\nVemos en la consola la salida de nuestro proyecto\nDefiniendo KafkaTemplate para enviar mensajes JSON #Dijimos antes que cuando definimos KafkaTemplate, indicamos el tipo de mensaje el el value .\nKafkaTemplate\u0026lt;K, V\u0026gt; Por lo que podemos también definir como tipo de mensaje una clase y que ese objeto viaje como un Json. En este ejemplo, queremos enviar un objeto de tipo User serializado en Json.\nAquí, en la config definimos JsonSerializer como Serializer del valor.\n@Configuration public class KafkaJsonConfig { public ProducerFactory\u0026lt;String, User\u0026gt; producerFactoryJson() { Map\u0026lt;String, Object\u0026gt; config = new HashMap\u0026lt;\u0026gt;(); config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, \u0026#34;127.0.0.1:9092\u0026#34;); config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return new DefaultKafkaProducerFactory\u0026lt;\u0026gt;(config); } @Bean(name = \u0026#34;kafkaJsonTemplate\u0026#34;) public KafkaTemplate\u0026lt;String, User\u0026gt; kafkaTemplateJson() { return new KafkaTemplate\u0026lt;\u0026gt;(producerFactoryJson()); } } Definiendo un producer y el consumer para mensajes Json #Observa que aquí usamos KafkaTemplate que definimos para que reciba una clase.\nKafkaTemplate\u0026lt;String, User\u0026gt; @Component public class KafkaJsonProducer { private static final Logger LOGGER = LoggerFactory.getLogger(KafkaJsonProducer.class); private final KafkaTemplate\u0026lt;String, User\u0026gt; kafkaTemplate; public KafkaJsonProducer(@Qualifier(\u0026#34;kafkaJsonTemplate\u0026#34;) KafkaTemplate\u0026lt;String, User\u0026gt; kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } public void sendMessage(User user) { LOGGER.info(\u0026#34;Producing message {}\u0026#34;, user); this.kafkaTemplate.send(\u0026#34;TOPIC-DEMO-JSON\u0026#34;, user); } } El consumer es igual que el primero que definimos. Solo que enviamos una clase User y a un tópico diferente.\n@Component public class KafkaJsonConsumer { Logger logger = LoggerFactory.getLogger(KafkaJsonConsumer.class); @KafkaListener(topics = \u0026#34;TOPIC-DEMO-JSON\u0026#34;, groupId = \u0026#34;group_id\u0026#34;) public void consume(User message) { logger.info(\u0026#34;Consuming Message {}\u0026#34;, message); } } Probando el envío de Json a Kafka #Enviaremos a Kafka una instancia de User .\npublic class User { private String name; public User() { } public User(String name) { this.name = name; } // set, get .. @Override public String toString() { return \u0026#34;User{\u0026#34; + \u0026#34;name=\u0026#39;\u0026#34; + name + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#39;}\u0026#39;; } } @Component public class CommandLineAppStartupRunner implements CommandLineRunner { private final KafkaJsonProducer jsonProducer; public CommandLineAppStartupRunner(KafkaJsonProducer jsonProducer) { this.jsonProducer = jsonProducer; } @Override public void run(String... args) throws Exception { jsonProducer.sendMessage(new User(\u0026#34;Larry\u0026#34;)); jsonProducer.sendMessage(new User(\u0026#34;The Edge\u0026#34;)); jsonProducer.sendMessage(new User(\u0026#34;Charly\u0026#34;)); } } Observamos el resultado en la consola.\nEnviando un ACK Acknowledgment al recibir el mensaje en el consumer de Kafka #Si deseamos podemos establecer el auto commit como falso para los un consumer. Esto hará que debamos enviar un ack indicando que recibimos ok el mensaje en nuestro listener.\nDebemos deshabilitar el auto-commit por configuración o por property. Ambas opciones son igual de válidas.\nPor application.properties\nspring.kafka.consumer.enable-auto-commit=false Por configuración.\nCómo enviamos el ack en nuestro listener de Kafka #Teniendo ya la configuración para que no haga auto-commit. Indicamos el ack en el listener de este modo.\nConclusión #En este Post configuramos Spring Boot con Kafka. Para los objetos indicamos un Json serializer a fin de enviar el mensaje en formato Json. Enviamos mensajes mediante un consumer a un tópico y lo recibimos en un consumer mediante un listener. También respondimos un ack en nuestro consumer para avisar que recibimos ok el mensaje.\nCódigo fuente de este ejemplo #Como siempre te dejo el código fuente de este ejemplo para que lo tengas a mano.\nhttps://github.com/gustavopeiretti/spring-boot-examples/tree/master/spring-boot-kafka\n","date":"15 jun 2021","permalink":"https://gustavopeiretti.com/configurar-kafka-en-spring-boot/","section":"Posts","summary":"\u003cp\u003eVeamos en este post como implementar y configurar \u003ca href=\"https://kafka.apache.org/\" target=\"_blank\" rel=\"noreferrer\"\u003eApache Kafka\u003c/a\u003e con SpringBoot. \u003cbr\u003e\u003c/p\u003e\n\u003cp\u003eSpring provee una forma simple de integrarse con Kafka para enviar mensajes.\nMediante anotaciones podemos recibir los mensajes de Kafka y a través del uso de un  \u003cem\u003etemplate\u003c/em\u003e enviamos fácilmente los mensajes.\u003c/p\u003e","title":"Configurar Kafka en SpringBoot"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/kafka/","section":"Tags","summary":"","title":"Kafka"},{"content":"Examinaremos aquí cómo utilizar Spring WebClient para realizar llamadas a un servicio enviando solicitudes.\n¿Qué es Spring WebClient? #WebClient provee una interfaz común para realizar solicitudes web de un modo no bloqueante. Forma parte del módulo de Spring Web Reactive y es el reemplazo del conocido RestTemplate. Veremos a continuación las dependencias que necesitamos, como crear un cliente web y algunas configuraciones más que podemos usar con Spring WebClient.\n¿Qué dependencias necesitamos para utilizar Spring WebClient? #Lo primero que necesitamos es definir las dependencias.\nspring-boot-starter-webflux es la dependencia necesaria para el webclient mockserver-netty lo usaremos para mockear el web server en las pruebas unitarias para este ejemplo \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-webflux\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-test\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;exclusions\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.junit.vintage\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;junit-vintage-engine\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;/exclusions\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.mock-server\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mockserver-netty\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;5.11.1\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; La estructura de este ejemplo se ve así # ¿Cómo crear un WebClient? #Para utilizar WebClient nos valdremos del builder que nos provee WebClient WebClient.builder()\nDe este modo vamos a crear una instancia de WebClient con una url base.\nWebClient webClient = WebClient.builder() .baseUrl(\u0026#34;http://localhost:8899\u0026#34;) .build(); ¿Cómo agregar headers por default al WebClient? #Comúnmente, cuando se trata de llamadas con un body Json, se agrega el header indicando que es una llamada application/json .\nPodemos indicar headers por default.\nWebClient webClient = WebClient.builder() .baseUrl(\u0026#34;https://run.mocky.io\u0026#34;) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .build(); ¿Cómo enviar un request y recibir un response con WebClient? #Una vez que tenemos nuestra instancia de WebClient podemos enviar una petición.\nEn este ejemplo tenemos nuestro request que hemos definido como ClientRequest y nuestro response en ClientResponse.\nEstaremos enviando un POST a una uri mediante webClient.post().uri(\u0026hellip;)\nEl método retrieve ejecuta el HTTP request y devuelve la respuesta.\nEl método bodyToMono toma el body del retrieve y lo convierte en nuestra clase de response que le especifiquemos.\nClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() .bodyToMono(ClientResponse.class) .block(); ¿Cómo configurar un timeout en el WebClient? #Podemos configurar el timeout del nuestro WebClient indicando una duración en segundos o cualquier otra duración que provea la clase Duration .\nClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() .bodyToMono(ClientResponse.class) .timeout(Duration.ofSeconds(3)) // timeout .block(); Otra forma de especificar un timeout es a través de la configuración de un TcpClient en donde podemos ser más específicos.\nA continuación vemos la especificación de un timeout para la conexión y lectura / escritura del WebClient.\n// tcp client timeout TcpClient tcpClient = TcpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) .doOnConnected(connection -\u0026gt; connection.addHandlerLast(new ReadTimeoutHandler(3)) .addHandlerLast(new WriteTimeoutHandler(3))); WebClient webClient = WebClient.builder() .baseUrl(\u0026#34;http://localhost:8899\u0026#34;) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient))) // timeout .build(); ClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() .bodyToMono(ClientResponse.class) .block(); return response; Manejar los http status en el WebClient #Podemos conocer y manejar cualquier http status en nuestro WebClient utilizando el método onStatus.\nPor ejemplo, aquí ante un error 500 logueamos y tiramos un error usando onStatus(\u0026hellip;) tirando una exception nuestra ApiWebClientException\nVeamos lo que hacemos a continuation, hay mucho aquí:\nCreamos nuestro webclient Indicamos que hará un POST Recibirá un request de nuestra clase ClientRequest Hará un retrieve ejecutando así el HTTP request Si ocurre un error HttpStatus 500 lo evaluará en onStatus y decidirá que hacer con ese error. Convertirá la respuesta hacia nuestra clase ClientResponse Esperará 3 segundos como máximo para la conexión. ClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() // handle status .onStatus(HttpStatus::is5xxServerError, clientResponse -\u0026gt; { logger.error(\u0026#34;Error endpoint with status code {}\u0026#34;, clientResponse.statusCode()); throw new ApiWebClientException(\u0026#34;HTTP Status 500 error\u0026#34;); // throw custom exception }) .bodyToMono(ClientResponse.class) .timeout(Duration.ofSeconds(3)) // timeout .block(); Como queda nuestro web client terminado #Sumando todo lo visto antes nuestro web client nos queda así.\n@Component public class ApiWebClient { private static final Logger logger = LoggerFactory.getLogger(ApiWebClient.class); public ClientResponse createClient(ClientRequest request) { // tcp client timeout TcpClient tcpClient = TcpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000) .doOnConnected(connection -\u0026gt; connection.addHandlerLast(new ReadTimeoutHandler(3)) .addHandlerLast(new WriteTimeoutHandler(3))); WebClient webClient = WebClient.builder() .baseUrl(\u0026#34;http://localhost:8899\u0026#34;) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient))) // timeout .build(); ClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() // handle status .onStatus(HttpStatus::is5xxServerError, clientResponse -\u0026gt; { logger.error(\u0026#34;Error endpoint with status code {}\u0026#34;, clientResponse.statusCode()); throw new ApiWebClientException(\u0026#34;HTTP Status 500 error\u0026#34;); // throw custom exception }) .bodyToMono(ClientResponse.class) .block(); return response; } public ClientResponse createClientWithDuration(ClientRequest request) { WebClient webClient = WebClient.builder() .baseUrl(\u0026#34;http://localhost:8899\u0026#34;) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .build(); ClientResponse response = webClient.post() .uri(\u0026#34;/accounts\u0026#34;) .body(Mono.just(request), ClientRequest.class) .retrieve() // handle status .onStatus(HttpStatus::is5xxServerError, clientResponse -\u0026gt; { logger.error(\u0026#34;Error endpoint with status code {}\u0026#34;, clientResponse.statusCode()); throw new ApiWebClientException(\u0026#34;HTTP Status 500 error\u0026#34;); // throw custom exception }) .bodyToMono(ClientResponse.class) .timeout(Duration.ofSeconds(3)) // timeout .block(); return response; } } Como crear un test para probar Spring WebClient #Primero definimos un test de Spring en el que usaremos MockServer .\nPor cada test levantamos un server en el puerto 8899 y al finalizar cada test lo paramos.\nVamos a crear varios test para probar diferentes casos. Probaremos:\nUna conexión correcta. Una conexión con un timeout expirado. Una conexión que tira un error 500 y devuelve una un error ApiWebClientException Observa a continuación que levantamos el mock del servidor y luego lo paramos.\nClientAndServer mockServer = ClientAndServer.startClientAndServer(8899); mockServer.stop(); Luego seteamos las expectativas que queremos para el server.\nEn este ejemplo, indicamos que cuando ocurra un POST para el path /account responda con el body que indicamos, el header y con un tiempo de demora.\nmockServer.when(HttpRequest.request().withMethod(\u0026#34;POST\u0026#34;) .withPath(\u0026#34;/accounts\u0026#34;)). respond(HttpResponse.response() .withBody(\u0026#34;{ \\\u0026#34;name\\\u0026#34;: \\\u0026#34;Frank\\\u0026#34;, \\\u0026#34;email\\\u0026#34;: \\\u0026#34;frank@mail.com\\\u0026#34;}\u0026#34;) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .withDelay(TimeUnit.MILLISECONDS, 5000)); Veamos como queda los unit test para los distintos casos.\n@SpringBootTest public class ClientServiceTest { private static final Logger logger = LoggerFactory.getLogger(ClientServiceTest.class); @Autowired private ApiWebClient webClient; private ClientAndServer mockServer; @BeforeEach public void startServer() { mockServer = ClientAndServer.startClientAndServer(8899); } @AfterEach public void stopServer() { mockServer.stop(); } @Test void createShouldReturnTheResponse() { // set up mock server with a delay of 1 seconds mockServer.when(HttpRequest.request().withMethod(\u0026#34;POST\u0026#34;) .withPath(\u0026#34;/accounts\u0026#34;)). respond(HttpResponse.response() .withBody(\u0026#34;{ \\\u0026#34;name\\\u0026#34;: \\\u0026#34;Frank\\\u0026#34;, \\\u0026#34;email\\\u0026#34;: \\\u0026#34;frank@mail.com\\\u0026#34;}\u0026#34;) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .withDelay(TimeUnit.MILLISECONDS, 1000)); ClientRequest request = new ClientRequest(); request.setName(\u0026#34;Frank\u0026#34;); request.setName(\u0026#34;frank@mail.com\u0026#34;); ClientResponse response = webClient.createClient(request); assertThat(response).isNotNull(); assertThat(response.getName()).isEqualTo(\u0026#34;Frank\u0026#34;); assertThat(response.getEmail()).isEqualTo(\u0026#34;frank@mail.com\u0026#34;); } @Test void createWithTimeoutShouldThrowReadTimeOut() { // set up mock server with a delay of 5 seconds mockServer.when(HttpRequest.request().withMethod(\u0026#34;POST\u0026#34;) .withPath(\u0026#34;/accounts\u0026#34;)). respond(HttpResponse.response() .withBody(\u0026#34;{ \\\u0026#34;name\\\u0026#34;: \\\u0026#34;Frank\\\u0026#34;, \\\u0026#34;email\\\u0026#34;: \\\u0026#34;frank@mail.com\\\u0026#34;}\u0026#34;) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .withDelay(TimeUnit.MILLISECONDS, 5000)); ClientRequest request = new ClientRequest(); request.setName(\u0026#34;Frank\u0026#34;); request.setName(\u0026#34;frank@mail.com\u0026#34;); assertThrows(ReadTimeoutException.class, () -\u0026gt; webClient.createClient(request)); } @Test void createWithStatusShouldThrowACustomException() { // set up mock server with a http status 500 mockServer.when(HttpRequest.request().withMethod(\u0026#34;POST\u0026#34;) .withPath(\u0026#34;/accounts\u0026#34;)) .respond(HttpResponse.response().withStatusCode(500) .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .withDelay(TimeUnit.MILLISECONDS, 1000)); ClientRequest request = new ClientRequest(); request.setName(\u0026#34;Frank\u0026#34;); request.setName(\u0026#34;frank@mail.com\u0026#34;); ApiWebClientException apiWebClientException = assertThrows(ApiWebClientException.class, () -\u0026gt; webClient.createClient(request)); assertTrue(apiWebClientException.getMessage().contains(\u0026#34;HTTP Status 500 error\u0026#34;)); } } Conclusión #Vimos cómo crear de forma simple un cliente web usando Spring WebClient. Examinamos cómo configurar el cliente, enviar una solicitud y recibir la respuesta.\nPuedes ver este código en: https://github.com/gustavopeiretti/spring-boot-examples\n","date":"26 oct 2020","permalink":"https://gustavopeiretti.com/spring-boot-como-usar-webclient/","section":"Posts","summary":"\u003cp\u003eExaminaremos aquí cómo utilizar Spring WebClient para realizar llamadas a un servicio enviando solicitudes.\u003c/p\u003e","title":"Spring Boot - Como usar WebClient"},{"content":"Spring Boot Retry ofrece una forma simple para reintentar alguna operación que ha fallado. Esto es útil sobre todo cuando se tratan errores temporales o transitorios como el acceso a un recurso externo.\nSpring Boot Retry puede configurarse de forma declarativa mediante anotaciones o definiendo una config general.\nVamos a ver aquí cómo utilizar la funcionalidad Retry dentro de SpringBoot.\nDependencias necesarias para Spring Boot Retry #Las dependencias que necesitas son las siguientes\n\u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.retry\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-retry\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.3.0\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-aop\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; Como activar Retry en Spring Boot #Para activar Spring Retry debes anotar tu aplicación @EnableRetry\n@SpringBootApplication @EnableRetry public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } Como indicar que un método es ‘reintentable’ #Para indicar que un método es reintentable usas esta anotación @Retryable de este modo. Puedes además establecer la máxima cantidad de intentos maxAttempts, y la demora entre intentos backoff entre otras opciones.\nPara recuperarse de un método que, a pesar de los reintentos, sigue fallando puedes anotar un método de recuperación @Recover que será llamado por Spring al agotar todos los intentos. Este método debe devolver el mismo tipo de dato que el método original. Observa que puedes recibir como primer parámetro la excepción y subsecuentemente el resto de parámetros del método que ha fallado.\nHemos definido una excepción propia, ante la cual deseamos que se realicen los reintentos.\npublic class ApiRetryException extends RuntimeException { public ApiRetryException(String message) { super(message); } } En este ejemplo si recibimos en nuestro método el parámetro \u0026ldquo;error\u0026rdquo;, provocamos intencionalmente un error.\n@Service public class RetryExampleService { private static Logger LOGGER = LoggerFactory.getLogger(RetryExampleService.class); @Retryable(value = {RuntimeException.class}, maxAttempts = 4, backoff = @Backoff(1000)) public String retryExample(String s) { LOGGER.info(\u0026#34;Retry retryTemplateExample {}\u0026#34;, LocalDateTime.now().getSecond()); if (s == \u0026#34;error\u0026#34;) { throw new ApiRetryException(\u0026#34;Error in RetryExampleService.retryExample \u0026#34;); } else { return \u0026#34;Hi \u0026#34; + s; } } @Recover public String retryExampleRecovery(RuntimeException t, String s) { LOGGER.info(\u0026#34;Retry Recovery - {}\u0026#34;, t.getMessage()); return \u0026#34;Retry Recovery OK!\u0026#34;; } } Probar Retry con un test #Vamos a probar si nuestro método puede recuperarse con @Recovery. Nuestro método de recuperación para este ejemplo simplemente devuelve un String “Retry Recovery OK!”\n@RunWith(SpringRunner.class) @SpringBootTest public class RetryExampleServiceTest { @Autowired private RetryExampleService retryExampleService; @Test public void retryExampleWithRecoveryTest() throws Exception { String result = retryExampleService.retryExample(\u0026#34;error\u0026#34;); Assert.assertEquals(\u0026#34;Retry Recovery OK!\u0026#34;, result); } } La salida de este test RetryExampleServiceTest\nINFO 74514 --- [main] com.gp.service.RetryExampleService : Retry retryTemplateExample 52 INFO 74514 --- [main] com.gp.service.RetryExampleService : Retry retryTemplateExample 53 INFO 74514 --- [main] com.gp.service.RetryExampleService : Retry retryTemplateExample 54 INFO 74514 --- [main] com.gp.service.RetryExampleService : Retry retryTemplateExample 55 INFO 74514 --- [main] com.gp.service.RetryExampleService : Retry Recovery - Error in RetryExampleService.retryExample Cómo definir un \u0026rsquo;template\u0026rsquo; para Retry usando RetryTemplate #Además de usar las anotaciones @Retryable y @Recover puedes crear un template en tu configuración para usarlo de manera general.\nPara definir un template para los Retry en tu config defines un bean usando org.springframework.retry.support.RetryTemplate. Básicamente tienes dos atributos importantes: cantidad de intentos y el tiempo entre reintentos.\nSi deseas puedes también definir un listener a partir de la clase RetryListenerSupport y registrarlo en el template.\nAquí definimos un reintento con un máximo de 4 intentos y 1000 milisegundos entre cada uno.\n@Configuration public class RetryConfig { @Bean public RetryTemplate retryTemplate() { return RetryTemplate.builder() .maxAttempts(4) .fixedBackoff(1000L) .retryOn(ApiRetryException.class) .withListener(new ApiRetryListener()) .build(); } } Para el listener extiendes de RetryListenerSupport en donde tienes definido tres métodos:\nopen cuando se inicia, onError al momento de producirse el error y reintentar y close cuando se agotaron todos los intentos o cuando finaliza porque ya no ocurrio ningún error. En el listener tienes un RetryContext del cual puedes obtener información o pasar datos entre tu método y el listener.\npublic class ApiRetryListener extends RetryListenerSupport { private static Logger LOGGER = LoggerFactory.getLogger(ApiRetryListener.class); @Override public \u0026lt;T, E extends Throwable\u0026gt; boolean open(RetryContext context, RetryCallback\u0026lt;T, E\u0026gt; callback) { LOGGER.info(\u0026#34;ApiRetryListener.open\u0026#34;); return super.open(context, callback); } @Override public \u0026lt;T, E extends Throwable\u0026gt; void onError(RetryContext context, RetryCallback\u0026lt;T, E\u0026gt; callback, Throwable throwable) { LOGGER.info(\u0026#34;ApiRetryListener.onError\u0026#34;); } @Override public \u0026lt;T, E extends Throwable\u0026gt; void close(RetryContext context, RetryCallback\u0026lt;T, E\u0026gt; callback, Throwable throwable) { LOGGER.info(\u0026#34;ApiRetryListener.close\u0026#34;); LOGGER.info(\u0026#34;ApiRetryListener.onError isExhausted {}\u0026#34;, isExhausted(context)); } private boolean isExhausted(RetryContext context) { return context.hasAttribute(RetryContext.EXHAUSTED); } private boolean isClosed(RetryContext context) { return context.hasAttribute(RetryContext.CLOSED); } private boolean isRecovered(RetryContext context) { return context.hasAttribute(RetryContext.RECOVERED); } } Luego para utilizar este template usas el bean que definiste llamando al método retryTemplate.execute(..)\nEste método recibe una interfaz RetryCallback en la que debes implementar doWithRetry y alli ejecutar tu código.\nretryTemplate.execute(new RetryCallback\u0026lt;String, RuntimeException\u0026gt;() { @Override public String doWithRetry(RetryContext retryContext) { // do process } }); Veamos esto con nuestro ejemplo.\n@Service public class RetryTemplateExampleService { private static Logger log = LoggerFactory.getLogger(RetryTemplateExampleService.class); private final RetryTemplate retryTemplate; @Autowired public RetryTemplateExampleService(RetryTemplate retryTemplate) { this.retryTemplate = retryTemplate; } public String retryTemplateExample(String s) { String result; result = retryTemplate.execute(new RetryCallback\u0026lt;String, RuntimeException\u0026gt;() { @Override public String doWithRetry(RetryContext retryContext) { // do something in this service log.info(String.format(\u0026#34;Retry retryTemplateExample %d\u0026#34;, LocalDateTime.now().getSecond())); if (s.equals(\u0026#34;error\u0026#34;)) { throw new ApiRetryException(\u0026#34;Error in process\u0026#34;); } else { return \u0026#34;Hi \u0026#34; + s; } } }); log.info(\u0026#34;Returning {}\u0026#34;, result); return result; } } Probar RetryTemplate con un test # @RunWith(SpringRunner.class) @SpringBootTest public class RetryTemplateExampleServiceTest { @Autowired private RetryTemplateExampleService retryTemplateExampleService; @Test(expected = ApiRetryException.class) public void retryTemplateExampleShouldThrowRuntime() throws Exception { retryTemplateExampleService.retryTemplateExample(\u0026#34;error\u0026#34;); } @Test public void retryTemplateExampleShouldReturnCorrectValue() throws Exception { String s = retryTemplateExampleService.retryTemplateExample(\u0026#34;word\u0026#34;); Assert.assertEquals(\u0026#34;Hi word\u0026#34;, s); } } La salida de este test\n// retryTemplateExampleShouldThrowRuntime INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.open INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Retry retryTemplateExample 1 INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Retry retryTemplateExample 2 INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Retry retryTemplateExample 4 INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Retry retryTemplateExample 5 INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.close INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError isExhausted true // retryTemplateExampleShouldReturnCorrectValue INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.open INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Retry retryTemplateExample 5 INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.close INFO 30304 --- [main] com.gp.config.ApiRetryListener : ApiRetryListener.onError isExhausted false INFO 30304 --- [main] c.g.service.RetryTemplateExampleService : Returning Hi word Conclusión #Hemos revisado cómo usar Spring Retry para reintentar alguna operación en nuestro código si ha fallado y cómo crear un método de recuperación si lo necesitaramos. Vimos que podemos definir esto simplemente con una anotación o con un template a usar.\nPuedes ver este código completo # github: spring-boot-examples\n","date":"18 sept 2020","permalink":"https://gustavopeiretti.com/spring-boot-retry/","section":"Posts","summary":"\u003cp\u003eSpring Boot Retry ofrece una forma simple para reintentar alguna operación que ha fallado.\nEsto es útil sobre todo cuando se tratan errores temporales o transitorios como el acceso a un recurso externo.\u003c/p\u003e\n\u003cp\u003eSpring Boot Retry puede configurarse de forma declarativa mediante anotaciones o definiendo una config general.\u003cbr\u003e\nVamos a ver aquí cómo utilizar la funcionalidad Retry dentro de SpringBoot.\u003c/p\u003e","title":"Como usar Spring Boot Retry"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/elasticsearch/","section":"Tags","summary":"","title":"Elasticsearch"},{"content":"En este ejemplo, vamos a entender cómo utilizar la geolocalización de ElasticSearch. Agregaremos documentos con geolocalización utilizando geo_point y buscaremos luego esos documentos mediante coordenadas.\nLa geolocalización de ElasticSearch es una herramienta muy útil que puede servirte por ejemplo para buscar comercios, clientes, etc, que están cerca de dónde se encuentra un usuario en un punto específico.\nCuáles son los pasos para crear un índice con geolocalización # Creas un índice con un POST y la propiedad properties:location Creas un documento con un POST completando la propiedad location Realizas la búsqueda con un GET con un filtro de distance y location Como crear el índice de geolocalización en Elasticsearch #Lo primero que necesitas es crear un índice en ElasticSearch con geolocalización.\nEl índice se llamará establishment y lo vas a definir con la propiedad geo_point a fin de que tenga el soporte de geolocalización.\nDefinir el PUT para crear un índice con geolocalización y ejecutarlo. Observa el type geo_point que está definido dentro de properties:location\ncurl --location --request PUT \u0026#39;http://localhost:9200/establishment\u0026#39; \\ --header \u0026#39;Content-Type: application/json\u0026#39; \\ --data-raw \u0026#39;{ \u0026#34;mappings\u0026#34;: { \u0026#34;properties\u0026#34;: { \u0026#34;location\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;geo_point\u0026#34; } } } } Como agregar documentos a elastic con geolocalización #En el índice establishment, creamos un documento con ID 1 e indicamos su localización.\nHaciendo un PUT al index agregas un documento con las coordenadas de geolocalización.\nObserva aquí, que dentro de location indican las coordenadas en latitud y longitud que tiene ese índice.\ncurl --location --request PUT \u0026#39;http://localhost:9200/establishment/_doc/1\u0026#39; \\ --header \u0026#39;Content-Type: application/json\u0026#39; \\ --data-raw \u0026#39;{ \u0026#34;text\u0026#34;: \u0026#34;Sports Shop ABC\u0026#34;, \u0026#34;location\u0026#34;: { \u0026#34;lat\u0026#34;: -31.397561, \u0026#34;lon\u0026#34;: -64.235415 } }\u0026#39; Aquí solo te muestro una sola inserción para simplificar, pero es conveniente que insertes varios documentos en distintas coordenadas (cerca y lejos de un punto) para visualizar mejor este ejemplo.\nBuscar documentos en elasticsearch con coordenadas de geolocalización #Luego puedes realizar búsquedas por cercanía utilizando kilómetros desde un punto de origen.\nObserva nuevamente los filtros que usamos para la búsqueda por geo_distance .\nUtilizando la distancia hasta donde deseamos buscar en distance y el punto desde el cual deseamos realizar la búsqueda en location .\ncurl --location --request GET \u0026#39;http://localhost:9200/establishment/_search\u0026#39; \\ --header \u0026#39;Content-Type: application/json\u0026#39; \\ --data-raw \u0026#39;{ \u0026#34;query\u0026#34;: { \u0026#34;bool\u0026#34; : { \u0026#34;must\u0026#34; : { \u0026#34;match_all\u0026#34; : {} }, \u0026#34;filter\u0026#34; : { \u0026#34;geo_distance\u0026#34; : { \u0026#34;distance\u0026#34; : \u0026#34;10km\u0026#34;, \u0026#34;location\u0026#34; : { \u0026#34;lat\u0026#34; : -31.397948, \u0026#34;lon\u0026#34; : -64.254007 } } } } } }\u0026#39; Conclusión #En este breve ejemplo vimos cómo crear un documento que contenga coordenadas de geolocalización. Utilizamos para ello la propiedad geo_point para crear un documento y luego buscarlo por cercanía.\nExisten otros tipos de busquedas que puedes examinar tambien, como la geo_shape que pueden proveerte otras formas de búsqueda por geolocalización.\nReferencias: #Índices con geo_point: Datatype geo-point\nBúsqueda por geo-distance utilizando la query geo_point: Search geo-point\n","date":"19 jun 2020","permalink":"https://gustavopeiretti.com/elastic-search-geolocalizacion/","section":"Posts","summary":"\u003cp\u003eEn este ejemplo, vamos a entender cómo utilizar la geolocalización de ElasticSearch.\nAgregaremos documentos con geolocalización utilizando \u003cem\u003egeo_point\u003c/em\u003e y buscaremos luego esos documentos mediante coordenadas.\u003c/p\u003e","title":"Elasticsearch - Como utilizar la geolocalización"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/java/","section":"Tags","summary":"","title":"Java"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/categories/java-core/","section":"Categories","summary":"","title":"Java Core"},{"content":"Para configurar un proyecto de Spring Batch partiremos con las dependencias que necesitamos utilizando Maven, luego definiremos la configuración básica y algunos aspectos simples para conectarnos a una base de datos embebida.\n¿Qué es Spring Batch? #Se trata de un framework destinado al proceso de grandes lotes de información en “modo batch”. La ejecución de procesos batch está enfocada en resolver el procesamiento sin intervención del usuario y de forma periódica.\nPero para explicarlo mejor, diremos que con Spring Batch podemos generar trabajos (job) y dividirlos en pasos (steps), como por ejemplo, leer datos de una base de datos para procesarlos aplicando alguna regla de negocio, y luego escribirlos en un archivo o de nuevo en la base de datos.\nVemos que un Job puede tener varios Step y cada Step un Reader, un Processor y un Writer.\n¿Qué harás en este ejemplo y para entender cómo funciona Spring Batch?\nConectarnos a una Base de Datos Leer todos los registros de una Tabla Procesar cada registro y generar nueva información Escribir el resultado del proceso en otra Tabla de la base de datos. Veamos las dependencias que necesitas.\nDependencias necesarias para Spring Batch #Para tu proyecto en Spring Batch necesitas la dependencia \u0026ldquo;org.springframework.boot:spring-boot-starter-batch\u0026rdquo; . Además para este ejemplo en el que usaremos una base de datos en memoria necesitamos la dependencia de \u0026ldquo;com.h2database:h2\u0026rdquo; También necesitarás \u0026ldquo;org.springframework.boot:spring-boot-starter-data-jpa\u0026rdquo; para conectar Spring Batch con la base de datos.\nEstas son todas las dependencias que usarás.\n\u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-batch\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.h2database\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;h2\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;runtime\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-test\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;exclusions\u0026gt; \u0026lt;exclusion\u0026gt; \u0026lt;groupId\u0026gt;org.junit.vintage\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;junit-vintage-engine\u0026lt;/artifactId\u0026gt; \u0026lt;/exclusion\u0026gt; \u0026lt;/exclusions\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.batch\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-batch-test\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-data-jpa\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;RELEASE\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;compile\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-data-jpa\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;RELEASE\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;compile\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; Estructura general de tu proyecto Spring Batch #Tu proyecto Spring Batch lucirá de la siguiente manera para este ejemplo .\n¿Que harás con este tutorial para crear una aplicación Spring Batch? #Lo que haremos en este ejemplo de proyecto será crear un Job que lea de una tabla contenido de tarjetas de crédito, luego al procesarlas determine en base a una supuesta fecha de pago el riesgo de la tarjeta, y al finalizar guarde otra entidad con el resultado.\n¿Que harás en este ejemplo?\nLeer de la base de datos las tarjetas de crédito Procesar las tarjetas y aplicar una regla de negocio para dichas tarjetas. El proceso debe generar una nueva entidad con el resultado del riesgo Al finalizar se guarda el resultado del proceso Las Entidades #Define dos entidades, una para la CreditCard y otra para CreditCardRisk\npackage dev.experto.demo.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.util.Date; @Entity public class CreditCard { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long cardNumber; private Date lastPay; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getCardNumber() { return cardNumber; } public void setCardNumber(Long cardNumber) { this.cardNumber = cardNumber; } public Date getLastPay() { return lastPay; } public void setLastPay(Date lastPay) { this.lastPay = lastPay; } @Override public String toString() { return \u0026#34;CreditCard{\u0026#34; + \u0026#34;id=\u0026#34; + id + \u0026#34;, cardNumber=\u0026#34; + cardNumber + \u0026#34;, lastPay=\u0026#34; + lastPay + \u0026#39;}\u0026#39;; } } package dev.experto.demo.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import java.util.Date; @Entity public class CreditCardRisk { public static final int HIGH = 3; public static final int LOW = 2; public static final int NORMAL = 1; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Date date; private int risk; @OneToOne(optional = false) private CreditCard creditCard; public CreditCardRisk() { } public CreditCardRisk(CreditCard creditCard, Date date, int risk) { this.creditCard = creditCard; this.date = date; this.risk = risk; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public int getRisk() { return risk; } public void setRisk(int risk) { this.risk = risk; } public CreditCard getCreditCard() { return creditCard; } public void setCreditCard(CreditCard creditCard) { this.creditCard = creditCard; } @Override public String toString() { return \u0026#34;CreditCardRisk{\u0026#34; + \u0026#34;id=\u0026#34; + id + \u0026#34;, date=\u0026#34; + date + \u0026#34;, risk=\u0026#34; + risk + \u0026#39;}\u0026#39;; } } Los Repository #Tendrás dos repository uno para cada entidad que usaremos luego dentro del ItemReader y del ItemWriter\npackage dev.experto.demo.repository; import dev.experto.demo.domain.CreditCard; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface CreditCardRepository extends JpaRepository\u0026lt;CreditCard, Long\u0026gt; { } package dev.experto.demo.repository; import dev.experto.demo.domain.CreditCardRisk; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface CreditCardRiskRespository extends JpaRepository\u0026lt;CreditCardRisk, Long\u0026gt; { } El Reader #Existen muchas implementaciones para los Reader en Spring Batch disponibles para leer distintas fuentes de datos (ej. archivos, base de datos).\nAquí crearás una propia, a partir de la interfaz principal ItemReader .\nDefinimos el reader que implementará ItemReader y que usará un repositorio de Spring para obtener todas las CreditCard\nCon la anotación BeforeStep realizamos una operación de lectura sobre la base de datos previo a iniciar el Reader.\nEl método read() irá entregando cada ítem de la lista al Processor .\nimport dev.experto.demo.domain.CreditCard; import dev.experto.demo.repository.CreditCardRepository; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.annotation.BeforeStep; import org.springframework.batch.item.ItemReader; import org.springframework.beans.factory.annotation.Autowired; import java.util.Iterator; public class CreditCardItemReader implements ItemReader\u0026lt;CreditCard\u0026gt; { @Autowired private CreditCardRepository respository; private Iterator\u0026lt;CreditCard\u0026gt; usersIterator; @BeforeStep public void before(StepExecution stepExecution) { usersIterator = respository.findAll().iterator(); } @Override public CreditCard read() { if (usersIterator != null \u0026amp;\u0026amp; usersIterator.hasNext()) { return usersIterator.next(); } else { return null; } } } El Processor #El Processor se encargará de recibir una CreditCard y entregar una CreditCardRisk\nimport dev.experto.demo.domain.CreditCard; import dev.experto.demo.domain.CreditCardRisk; import org.springframework.batch.item.ItemProcessor; import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; import static java.time.temporal.ChronoUnit.DAYS; public class CreditCardItemProcessor implements ItemProcessor\u0026lt;CreditCard, CreditCardRisk\u0026gt; { @Override public CreditCardRisk process(CreditCard item) { LocalDate today = LocalDate.now(); LocalDate lastDate = item.getLastPay().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); long daysBetween = DAYS.between(today, lastDate); int risk; if (daysBetween \u0026gt;= 20) { risk = CreditCardRisk.HIGH; } else if (daysBetween \u0026gt; 10) { risk = CreditCardRisk.LOW;; }else { risk = CreditCardRisk.NORMAL;; } CreditCardRisk creditCardRisk = new CreditCardRisk(item, new Date(), risk); return creditCardRisk; } } El Writer #El Writer también tiene muchas implementaciones en Spring Batch que puedes utilizar según sea qué o dónde estés escribiendo.\nAl igual que hicimos para el Reader, crearemos nuestro propio Writer a partir de la interfaz. El Writer recibirá la lista de CreditCardRisk que el Processor ha procesado para guardar el resultado en la base de datos.\nimport dev.experto.demo.domain.CreditCardRisk; import dev.experto.demo.repository.CreditCardRiskRespository; import org.springframework.batch.item.ItemWriter; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; public class CreditCardItemWriter implements ItemWriter\u0026lt;CreditCardRisk\u0026gt; { @Autowired private CreditCardRiskRespository respository; @Override public void write(List\u0026lt;? extends CreditCardRisk\u0026gt; list) throws Exception { respository.saveAll(list); } } Los Listeners #Los Listeners interceptan partes del proceso del Job y reciben o escuchan lo que está pasando durante la ejecución. Spring Batch dispone de numerosos listeners para cada parte del paso del job y puedes recurrir a ellos para conocer qué sucede en cada etapa.\nPor ejemplo, la siguiente interfaz JobExecutionListener escucha la ejecución previamente a empezar el job y luego de haber terminado el Job.\npublic interface JobExecutionListener { void beforeJob(JobExecution var1); void afterJob(JobExecution var1); } Implementa a continuación los listeners más comunes para entenderlos.\npackage dev.experto.demo.listener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionListener; import org.springframework.stereotype.Component; @Component public class CreditCardJobExecutionListener implements JobExecutionListener { private static final Logger LOGGER = LoggerFactory.getLogger(CreditCardJobExecutionListener.class); @Override public void beforeJob(JobExecution jobExecution) { LOGGER.info(\u0026#34;beforeJob\u0026#34;); } @Override public void afterJob(JobExecution jobExecution) { LOGGER.info(\u0026#34;afterJob: \u0026#34; + jobExecution.getStatus()); } } package dev.experto.demo.listener; import dev.experto.demo.domain.CreditCard; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.ItemReadListener; public class CreditCardIItemReaderListener implements ItemReadListener\u0026lt;CreditCard\u0026gt; { private static final Logger LOGGER = LoggerFactory.getLogger(CreditCardIItemReaderListener.class); @Override public void beforeRead() { LOGGER.info(\u0026#34;beforeRead\u0026#34;); } @Override public void afterRead(CreditCard creditCard) { LOGGER.info(\u0026#34;afterRead: \u0026#34; + creditCard.toString()); } @Override public void onReadError(Exception e) { LOGGER.info(\u0026#34;onReadError\u0026#34;); } } package dev.experto.demo.listener; import dev.experto.demo.domain.CreditCard; import dev.experto.demo.domain.CreditCardRisk; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.ItemProcessListener; public class CreditCardItemProcessListener implements ItemProcessListener\u0026lt;CreditCard, CreditCardRisk\u0026gt; { private static final Logger LOGGER = LoggerFactory.getLogger(CreditCardItemProcessListener.class); @Override public void beforeProcess(CreditCard creditCard) { LOGGER.info(\u0026#34;beforeProcess\u0026#34;); } @Override public void afterProcess(CreditCard creditCard, CreditCardRisk creditCardRisk) { LOGGER.info(\u0026#34;afterProcess: \u0026#34; + creditCard + \u0026#34; ---\u0026gt; \u0026#34; + creditCardRisk); } @Override public void onProcessError(CreditCard creditCard, Exception e) { LOGGER.info(\u0026#34;onProcessError\u0026#34;); } } package dev.experto.demo.listener; import dev.experto.demo.domain.CreditCardRisk; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.ItemWriteListener; import java.util.List; public class CreditCardIItemWriterListener implements ItemWriteListener\u0026lt;CreditCardRisk\u0026gt; { private static final Logger LOGGER = LoggerFactory.getLogger(CreditCardIItemWriterListener.class); @Override public void beforeWrite(List\u0026lt;? extends CreditCardRisk\u0026gt; list) { LOGGER.info(\u0026#34;beforeWrite\u0026#34;); } @Override public void afterWrite(List\u0026lt;? extends CreditCardRisk\u0026gt; list) { for (CreditCardRisk creditCardRisk : list) { LOGGER.info(\u0026#34;afterWrite :\u0026#34; + creditCardRisk.toString()); } } @Override public void onWriteError(Exception e, List\u0026lt;? extends CreditCardRisk\u0026gt; list) { LOGGER.info(\u0026#34;onWriteError\u0026#34;); } } El archivo application.properties #Vas a configurar aquí la conexión a la base de datos. Este proyecto usa una base de datos H2 en memoria para simplificar la ejecución de este ejemplo.\nspring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # create, create-drop, validate, update spring.jpa.hibernate.ddl-auto = update El archivo data.sql #Spring busca por defecto los archivos con extensión sql dentro de la carpeta resources y los ejecuta. Este archivo a continuación completará la base de datos H2 en memoria con información previa al momento de iniciar la aplicación.\nDe este modo tenemos así datos para procesar en memoria previo al iniciar el Job.\n-- risk HIGH INSERT INTO credit_card (card_number,last_pay) VALUES (9991,CURRENT_DATE()-30); INSERT INTO credit_card (card_number,last_pay) VALUES (9992,CURRENT_DATE()-21); -- risk LOW INSERT INTO credit_card (card_number,last_pay) VALUES (9993,CURRENT_DATE()-20); INSERT INTO credit_card (card_number,last_pay) VALUES (9994,CURRENT_DATE()-11); -- risk NORMAL INSERT INTO credit_card (card_number,last_pay) VALUES (9995,CURRENT_DATE()-10); INSERT INTO credit_card (card_number,last_pay) VALUES (9996,CURRENT_DATE()-5); Los chunk en Spring Batch? #Este es un concepto que usarás al configurar los Job. Un chunk es una unidad de procesamiento. Con este valor le dices a Spring Batch que procese una determinada cantidad de registros y al completar la cantidad envíe todo al reader para hacer el commit. Nota que la clase la Interfaz Item reader tiene el metodo read que recibe una lista. Esta lista es la cantidad de chunk que fueron procesados previamente y cuya cantidad estableciste en la config del chunk .\nCómo configurar el Job en Spring Batch #Dijimos antes que para Spring Batch un Job contiene Steps y cada Step requiere generalmente (no siempre) un Reader, un Processor, y un Writer. Opcionalmente puedes agregar Listener para escuchar y saber que esta pasando en cada parte del proceso del batch.\nEl Reader lee datos. El Procesor recibe los datos del Reader y los procesa para luego entregarlos al Writer. El Writer recepta los datos que fueron procesados y se encarga de guardarlos. Los Listener que “escuchan” lo que sucede durante el proceso. Para este ejemplo usaremos algunos listener, los más comunes, que dijimos previamente. A continuación vas a crear una clase de configuración para definir todas las partes del Job.\nEsta clase la anotas con @Configuration y @EnableBatchProcessing\nDentro de la clase que llamarás JobBatchConfiguration debes definir:\nUn bean de Spring para el Reader CreditCardItemReader Un bean de Spring para el Processor CreditCardItemProcessor Un bean de Spring para el Writer CreditCardItemWriter Los bean para los Listeners CreditCardJobExecutionListener CreditCardItemReaderListener CreditCardItemProcessListener CreditCardItemWriterListener Presta atención a cómo defines el Job y el Step que se ejecutará dentro del Job. Al Job le indicamos el listener que escuchara y le establecemos el / los steps. En la definición del Step también le indicamos los listeners y cada uno de los beans que mencionamos para el reader, procesor y writer. El “chunk” lo establecimos arbitrariamente en 100. Este valor lo debes pensar acorde a la necesidad de tu proyecto.\npackage dev.experto.demo.config; import dev.experto.demo.domain.CreditCard; import dev.experto.demo.domain.CreditCardRisk; import dev.experto.demo.job.CreditCardItemProcessor; import dev.experto.demo.job.CreditCardItemReader; import dev.experto.demo.job.CreditCardItemWriter; import dev.experto.demo.listener.CreditCardItemProcessListener; import dev.experto.demo.listener.CreditCardIItemReaderListener; import dev.experto.demo.listener.CreditCardIItemWriterListener; import dev.experto.demo.listener.CreditCardJobExecutionListener; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.step.tasklet.TaskletStep; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableBatchProcessing public class JobBatchConfiguration { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; @Bean public CreditCardItemReader reader() { return new CreditCardItemReader(); } @Bean public CreditCardItemProcessor processor() { return new CreditCardItemProcessor(); } @Bean public CreditCardItemWriter writer() { return new CreditCardItemWriter(); } @Bean public CreditCardJobExecutionListener jobExecutionListener() { return new CreditCardJobExecutionListener(); } @Bean public CreditCardIItemReaderListener readerListener() { return new CreditCardIItemReaderListener(); } @Bean public CreditCardItemProcessListener creditCardItemProcessListener() { return new CreditCardItemProcessListener(); } @Bean public CreditCardIItemWriterListener writerListener() { return new CreditCardIItemWriterListener(); } @Bean public Job job(Step step, CreditCardJobExecutionListener jobExecutionListener) { Job job = jobBuilderFactory.get(\u0026#34;job1\u0026#34;) .listener(jobExecutionListener) .flow(step) .end() .build(); return job; } @Bean public Step step(CreditCardItemReader reader, CreditCardItemWriter writer, CreditCardItemProcessor processor, CreditCardIItemReaderListener readerListener, CreditCardItemProcessListener creditCardItemProcessListener, CreditCardIItemWriterListener writerListener) { TaskletStep step = stepBuilderFactory.get(\u0026#34;step1\u0026#34;) .\u0026lt;CreditCard, CreditCardRisk\u0026gt;chunk(100) .reader(reader) .processor(processor) .writer(writer) .listener(readerListener) .listener(creditCardItemProcessListener) .listener(writerListener) .build(); return step; } } Cómo ejecutar Spring Batch #Este proyecto está creado con maven .\nDesde una consola de linux dentro de la carpeta del proyecto.\n$ ./mvnw spring-boot:run Desde una consola windows dentro de la carpeta del proyecto.\n\u0026gt; mvnw spring-boot:run Observa con más detalle la salida del log.\nSe inicia el Job con el Step asociado y el listener. Se ejecuta el reader y el listener del reader. Se ejecuta el procesador y el listener del procesador. Se ejecuta el writer y el listener del writer. Conclusión: #Con la ayuda de este ejemplo has creado una aplicación Spring Batch haciendo uso de algunas de sus funcionalidades más importantes.\nSi necesitas crear procesos batch que ejecuta acciones desatendidas y de gran carga este es un excelente framework para cubrir este objetivo.\nCódigo fuente de este ejemplo #Como siempre te dejo el código fuente de este ejemplo para que lo tengas a mano.\nhttps://github.com/gustavopeiretti/springbatch-example\nhttps://gitlab.com/gustavopeiretti/springbatch-example\n","date":"2 ene 2020","permalink":"https://gustavopeiretti.com/como-crear-una-aplicacion-con-spring-batch/","section":"Posts","summary":"\u003cp\u003ePara configurar un proyecto de Spring Batch partiremos con las dependencias que necesitamos utilizando Maven, luego definiremos la configuración básica y algunos aspectos simples para conectarnos a una base de datos embebida.\u003c/p\u003e","title":"Como crear una aplicación con Spring Batch"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/spring-batch/","section":"Tags","summary":"","title":"Spring Batch"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/database/","section":"Tags","summary":"","title":"Database"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/docker/","section":"Tags","summary":"","title":"Docker"},{"content":"En este post vas a aprender como crear una aplicacion Spring Boot con una base de datos PostgreSQL para que se ejecute dentro de un contenedor Docker.\nVerás a continuación estos puntos para construir tu aplicación Spring Boot con una base de datos PostgreSQL en un contenedor Docker.\nYa hemos estado trabajando en otros post con Spring Boot, Java y Docker. Te dejo aquí algunos links que pueden ayudarte con este tema.\nSpring Boot y Docker Dependencias para Spring Boot con Postgresql #Para este tutorial vas a utilizar Gradle para administrar las dependencias y el build del proyecto. La estructura de tu proyecto quedará al finalizar de este modo:\nNecesitas definir las siguientes dependencias para utilizar Spring Boot con Postgresql:\n\u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; \u0026#39;org.springframework.boot:spring-boot-starter-data-jpa\u0026#39; \u0026#39;org.postgresql:postgresql\u0026#39; El archivo build.gradle completo queda así:\nplugins { id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.2.1.RELEASE\u0026#39; id \u0026#39;io.spring.dependency-management\u0026#39; version \u0026#39;1.0.8.RELEASE\u0026#39; id \u0026#39;java\u0026#39; } group = \u0026#39;com.example\u0026#39; version = \u0026#39;0.0.1-SNAPSHOT\u0026#39; sourceCompatibility = \u0026#39;1.8\u0026#39; repositories { mavenCentral() } dependencies { implementation \u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; implementation \u0026#39;org.springframework.boot:spring-boot-starter-data-jpa\u0026#39; runtimeOnly \u0026#39;org.postgresql:postgresql\u0026#39; testImplementation(\u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39;) { exclude group: \u0026#39;org.junit.vintage\u0026#39;, module: \u0026#39;junit-vintage-engine\u0026#39; } } test { useJUnitPlatform() } El main de Spring Boot para el proyecto #Debes definir el main de tu aplicación con la anotación @SpringBootApplication\n@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } El resto de componentes para el proyecto: modelo, repositorio, controller y propiedades #Modelo #Vas a crear una entidad User que será un modelo muy simple para almacenar en la base de datos PostgreSQL\nimport javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class UserModel { @Id @GeneratedValue private Long id; private String name; // set and get… } Repositorio #Creas un repositorio para nuestro modelo User. Extenderá la clase JpaRepository de Spring.\n@Repository public interface UserRespository extends JpaRepository\u0026lt;UserModel, Long\u0026gt; { } Controller #Creas un controller con rest points básicos para este ejemplo. Vas a definir tres endpoints:\n\u0026ldquo;/user/all\u0026rdquo; para devolver todos los user \u0026ldquo;/user/{id}\u0026rdquo; para devolver un solo User por el ID \u0026ldquo;/user/save\u0026rdquo; para guardar un User import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; @RestController public class UserController { private UserRespository userRespository; @Autowired public UserController(UserRespository userRespository) { this.userRespository = userRespository; } @GetMapping(\u0026#34;/user/all\u0026#34;) Iterable\u0026lt;UserModel\u0026gt; all() { return userRespository.findAll(); } @GetMapping(\u0026#34;/user/{id}\u0026#34;) UserModel userById(@PathVariable Long id) { return userRespository.findById(id).orElseThrow(() -\u0026gt; new ResponseStatusException( HttpStatus.NOT_FOUND)); } @PostMapping(\u0026#34;/user/save\u0026#34;) UserModel save(@RequestBody UserModel user) { return userRespository.save(user); } } Archivo application.properties #Defines en el archivo la configuración que tendrá la base de datos con la url de la conexión, el username y el password. Veremos más adelante que estos valores por default salen de la imagen PostgeSql que usaremos en el archivo de configuración del docker compose.\nLa propiedad spring.jpa.hibernate.ddl-auto tiene estas opciones create, create-drop, validate, update De la documentación de spring tenemos:\ncreate: crea el schema de la base de datos destruyendo los datos. create-drop: borra el schema al finalizar la sesión. validate: solo valida el schema sin realizar cambios en las tablas de base de datos. update: actualiza el schema con los cambios que hagas en tus entidades. Archivo _resources/application.properties _ .\nspring.datasource.url=jdbc:postgresql://dbpostgresql:5432/mydb spring.datasource.username=postgres spring.datasource.password=password spring.jpa.hibernate.ddl-auto=create Configuración de Docker para Spring Boot con PostgreSQL #El archivo Dockerfile #En el archivo de Dockerfile le daremos las siguientes instrucciones a Docker.\nFROM openjdk:8-jdk-alpine MAINTAINER gustavopeiretti.com VOLUME /tmp EXPOSE 8080 ADD build/libs/springbootpostgresqldocker-0.0.1-SNAPSHOT.jar springbootpostgresqldocker.jar ENTRYPOINT [\u0026#34;java\u0026#34;,\u0026#34;-Djava.security.egd=file:/dev/./urandom\u0026#34;,\u0026#34;-jar\u0026#34;,\u0026#34;/springbootpostgresqldocker.jar\u0026#34;] FROM: usas aqui una (imagen de Docker)[https://hub.docker.com/_/openjdk] con un jdk8 y un server linux alpine.\nMAINTAINER: datos de contacto\nVOLUME: la carpeta donde se trabajara\nEXPOSE: el puerto que se expondrá ADD : copia el jar file de nuestra aplicación springbootpostgresqldocker-0.0.1-SNAPSHOT.ja en el contenedor docker con el nombre springbootpostgresqldocker.jar ENTRYPOINT : ejecuta la sentencia al arrancar el contenedor docker\nEl archivo docker-compose.yml #Debes crear un archivo docker-compose.yml en el cual vas a establecer dos servicios.\nEl primer servicio que llamarás app hace referencia al servicio de SpringBoot que configuraste en el Dockerfile. Dentro de ese servicio la instrucción build indica que ese servicio viene del Dockerfile que previamente definiste.\nEl segundo servicio que llamarás dbpostgresql utiliza una imagen postgresql del hub de docker que docker descargará de allí. Dejamos el password, user, y nombre de la db que viene por defecto.\nversion: \u0026#39;3.1\u0026#39; services: app: container_name: app-springboot-postgresql image: app-springboot-postgresql build: ./ ports: - \u0026#34;8080:8080\u0026#34; depends_on: - dbpostgresql dbpostgresql: image: postgres ports: - \u0026#34;5432:5432\u0026#34; environment: - POSTGRES_PASSWORD=password - POSTGRES_USER=postgres - POSTGRES_DB=mydb Ejecutar SpringBoot con PostgreSQL en el contenedor Docker #Build de tu proyecto para crear el archivo jar #En este ejemplo estamos usando gradlew. Por lo que lo que debes hacer es un build de este modo:\n./gradlew build Esto dejará el archivo jar de tu proyecto en la carpeta /build/libs de tu proyecto.\nBuild de docker compose para crear la imagen y ejecutar la aplicación dentro de docker #Luego de haber hecho un build de tu proyecto y tener disponible el archivo jar, puedes lanzar el contenedor.\ndocker-compose up --build Probar tu aplicación Spring Boot + PostgreSQL + Docker #Recuerda que habíamos creado previamente un UserController con un post para guardar el User y un get para obtener los usuarios Ahora ejecutas este post. Observa que guardas un Usuario y el response te devuelve el mismo User con el id ya asignado.\nPost /user/save\ncurl -s -X POST \\ http://localhost:8080/user/save \\ -H \u0026#39;Content-Type: application/json\u0026#39; \\ -d \u0026#39;{\u0026#34;name\u0026#34;:\u0026#34;Moana\u0026#34;}\u0026#39; Luego haces un get con el ID que del nuevo usuario que guardaste previamente.\nGet /user/save\ncurl -s -X GET \\ http://localhost:8080/user/1 Conclusión: #En este post creaste una app simple con Spring Boot utilizando dos imágenes de Docker. La primera para el servicio de SpringBoot y la segunda para PostgreSQL. Ejecutaste el contenedor de Docker con las imágenes y luego guardaste un nuevo User en la base de datos PostgreSQL utilizando los rest point que definiste para el User.\nEl código : #Como siempre puedes ver este código en github y gitlab.\nhttps://github.com/gustavopeiretti/springboot-postgresql-docker-example\nhttps://gitlab.com/gustavopeiretti/springboot-postgresql-docker-example\n","date":"6 dic 2019","permalink":"https://gustavopeiretti.com/spring-boot-postgresql-docker-compose/","section":"Posts","summary":"\u003cp\u003eEn este post vas a aprender como crear una aplicacion Spring Boot con una base de datos PostgreSQL para que se ejecute dentro de un contenedor Docker.\u003c/p\u003e","title":"Spring Boot con PostgreSQL y Docker Compose"},{"content":"Aprenderemos cómo ejecutar un microservicio Spring Boot dentro de un contenedor Docker.\nDependencias mínimas de un microservicio Spring Boot #Lo primero que vamos a hacer es definir las dependencias que necesitamos. Spring Boot requiere al menos estas dependencias:\norg.springframework.boot:spring-boot-starter-web org.springframework.boot:spring-boot-starter-test La configuración para Gradle de estas dependencias es la siguiente:\nplugins { id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.1.9.RELEASE\u0026#39; id \u0026#39;io.spring.dependency-management\u0026#39; version \u0026#39;1.0.8.RELEASE\u0026#39; id \u0026#39;java\u0026#39; } group = \u0026#39;com.gustavopeiretti\u0026#39; version = \u0026#39;0.0.1-SNAPSHOT\u0026#39; sourceCompatibility = \u0026#39;1.8\u0026#39; repositories { mavenCentral() } dependencies { implementation \u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; } La configuración en Maven de estas mismas dependencias:\n\u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.9.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!-- lookup parent from repository --\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.gustavopeiretti\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;springbootdocker\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;springbootdocker\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;Demo project for Spring Boot with Docker\u0026lt;/description\u0026gt; \u0026lt;properties\u0026gt; \u0026lt;java.version\u0026gt;1.8\u0026lt;/java.version\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-web\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-test\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;build\u0026gt; \u0026lt;plugins\u0026gt; \u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;/project\u0026gt; Crear el microservicio Spring Boot #Debes crear la clase principal que iniciará SpringBoot.\nAnotamos esa clase con @SpringBootApplication.\nLa anotación @SpringBootApplication es equivalente a usar @Configuration + @EnableAutoConfiguration + @ComponentScan con sus atributos predeterminados. Revisa este otro post para más detalles sobre el main class\n@SpringBootApplication public class SpringbootdockerApplication { public static void main(String[] args) { SpringApplication.run(SpringbootdockerApplication.class, args); } } Luego crea un controlador \u0026lsquo;rest controller\u0026rsquo; que anotas con @RestController. Crea una clase Home y anota el método con @RequestMapping. El método home a continuación mapea el path base de tus servicios. Aquí puedes leer más sobre los RestController\n@RestController public class Home { @RequestMapping(\u0026#34;/\u0026#34;) public String home() { return \u0026#34;Hello Spring Boot with Docker\u0026#34;; } } Puedes ahora ejecutar la aplicación desde la consola.\nSi utilizas gradle -\u0026gt; gradle bootRun Si utiliza maven -\u0026gt; mvn spring-boot:run Si utiliza el wrapper de gradle -\u0026gt; ./gradlew bootRun Aquí vemos el inicio con ./gradlew bootRun Abre la URL localhost:8080. Para terminar la ejecución de SpringBoot con Gradle, presiona Ctrl + C: Si no puedes terminar gradlew cuando presionas ctrl + c, tendrás que abrir otra consola y ejecutar ./gradlew -stop\nCrea tu aplicación Spring Boot #Antes de continuar con los otros pasos, asegúrese de hacer un build del proyecto para poner a disposición el archivo jar que necesitaremos más tarde.\ncon gradle #Gradle deja el archivo jar en la carpeta \\build\\libs de tu proyecto con el nombre que tienes en el archivo settings.gradle\ngradlew build El nombre del archivo jar será el especificado en el archivo settings.gradle. con maven #Maven deja el archivo jar en la carpeta \\target de tu proyecto con el nombre que hayas definido en el artifactId tag de tu archivo pom.xml\nmvnw package Crear un archivo Docker para ejecutar SpringBoot #Bien, ya tienes tu aplicación en ejecución. Ahora comenzarás a configurar Docker para que tu servicio se ejecute allí. Para crear la configuración Docker para SpringBoot, cree un archivo de texto Dockerfile con estas instrucciones:\nFROM openjdk:8-jdk-alpine VOLUME /tmp EXPOSE 8080 ARG JAR_FILE=build/libs/springbootdocker-0.0.1-SNAPSHOT.jar ADD ${JAR_FILE} app.jar ENTRYPOINT [\u0026#34;java\u0026#34;,\u0026#34;-Djava.security.egd=file:/dev/./urandom\u0026#34;,\u0026#34;-jar\u0026#34;,\u0026#34;/app.jar\u0026#34;] Veamos que estamos haciendo en cada línea:\nFROM: En la primera línea le indicamos que genere una imagen docker que ya está preestablecida con linux y Java 8. Es decir, nuestro servicio se ejecutará en un sistema linux y Java 8.\nADD: La instrucción ADD copia nuestra aplicación en Docker. Nuestra configuración gradle o maven deja el archivo jar de con todo nuestro código con el nombre \u0026ldquo;springbootdocker-0.0.1-SNAPSHOT. jar\u0026rdquo;. Este archivo jar springbootdocker-0.0.1-SNAPSHOT. se agrega al contenedor con la instrucción ADD con el nombre app.jar Si la ruta de su aplicación jar está en otro lugar, debe modificarla con la ruta correcta. En caso de que haya creado su aplicación con maven, debe usar la ruta del destino maven.\nENTRYPOINT: Luego ejecutamos el archivo al iniciar docker con la instrucción ENTRYPOINT\nUna vez definido el archivo Dockerfile, se ejecuta docker build.\nEl parámetro -t define el nombre que le daremos al contenedor y que utilizaremos posteriormente para ejecutarlo. El punto final para indicar la ubicación actual, desde donde se corre el comando.\ndocker build -t springbootdockerexample . Busque en la consola lo que sucede con la configuración de Docker que creó. En cada paso se ve que se genera la imagen de linux con java 8 (FROM), después de que el puerto 8080 es expuesto desde el contenedor al host contenedor (EXPOSE), el jar (ADD) es copiado y ejecutado (ENTRYPOINT).\nUna vez finalizada la construcción del docker, puede ejecutarlo con el nombre que le dio.\nEjecutar Docker con Spring Boot #Una vez que tenga la imagen docker, puede ejecutarlo con docker run El parámetro -p le dice a Docker que exponga el puerto 8080 de nuestra aplicación que se ejecuta dentro del contenedor, en el puerto 5000 del sistema operativo.\ndocker run -p 5000:8080 springbootdockerexample Ahora abre la URL que apunta al puerto que le dijo a docker. En este caso 5000 http://localhost:5000/\n¡Sonría, tu aplicación está ya funcionando en un contenedor Docker! Crea la imagen de Docker con Spring Boot usando Gradle #Si usas Gradle puedes agregar un plugin para construir la imagen y ejecutarla directamente desde los comandos de Gradle. Para esto, modifica el build.gradle añadiendo este plugin https://github.com/palantir/gradle-docker\nLo nuevo que se añade es lo que se ve en buildscript, a continuación, el apply del plugin y, finalmente, una nueva tarea \u0026lsquo;docker\u0026rsquo;.\n// docker: new plugin buildscript { dependencies { classpath \u0026#34;gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.22.1\u0026#34; } } plugins { id \u0026#39;org.springframework.boot\u0026#39; version \u0026#39;2.1.9.RELEASE\u0026#39; id \u0026#39;io.spring.dependency-management\u0026#39; version \u0026#39;1.0.8.RELEASE\u0026#39; id \u0026#39;java\u0026#39; } group = \u0026#39;com.gustavopeiretti\u0026#39; version = \u0026#39;0.0.1-SNAPSHOT\u0026#39; sourceCompatibility = \u0026#39;1.8\u0026#39; repositories { mavenCentral() } dependencies { implementation \u0026#39;org.springframework.boot:spring-boot-starter-web\u0026#39; testImplementation \u0026#39;org.springframework.boot:spring-boot-starter-test\u0026#39; } // docker: plugin apply apply plugin: \u0026#39;com.palantir.docker\u0026#39; // docker: new task docker docker { dependsOn build name \u0026#34;${project.name}\u0026#34; files bootJar.archivePath buildArgs([\u0026#39;JAR_FILE\u0026#39;: \u0026#34;${bootJar.archiveName}\u0026#34;]) } Analicemos la nueva tarea docker del archivo de compilación gradlew que hemos modificado:\ndependsOn build le decimos que esta tarea depende del build de gradle, deberá ocurrir primero el build. name \u0026ldquo;${project.name}\u0026rdquo; será el nombre del contenedor, le daremos el nombre del proyecto que tenemos en settings.gradle files bootJar.archivePath hará que el archivo jar generado por la compilación esté disponible buildArgs ([\u0026lsquo;JAR_FILE\u0026rsquo;: \u0026ldquo;$ {bootJar.archiveName}\u0026rdquo;]) envía como argumento el nombre del fichero jar. Ejecución de la imágen Docker con Spring Boot usando Gradle #Si ya has modificado tu archivo build añadiendo el plugin com.palantir.docker , puedes ejecutar directamente el build y crear tu imagen desde gradle. Desde su consola, debes usar gradlew build docker para construir una imagen.\ngradlew build docker docker run -p 5000:8080 springbootdocker Crear la imagen de Docker con Spring Boot usando Maven #En el caso de usar Maven, debe agregar este plugin si desea crear la imagen directamente desde mvn https://github.com/spotify/dockerfile-maven\n\u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;com.spotify\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;dockerfile-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.4.9\u0026lt;/version\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;repository\u0026gt;${project.artifactId}\u0026lt;/repository\u0026gt; \u0026lt;buildArgs\u0026gt; \u0026lt;JAR_FILE\u0026gt;target/${project.build.finalName}.jar\u0026lt;/JAR_FILE\u0026gt; \u0026lt;/buildArgs\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;id\u0026gt;default\u0026lt;/id\u0026gt; \u0026lt;phase\u0026gt;install\u0026lt;/phase\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;build\u0026lt;/goal\u0026gt; \u0026lt;goal\u0026gt;push\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; Tu pom.xml completo se ve así:\n\u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;parent\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-parent\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;2.1.9.RELEASE\u0026lt;/version\u0026gt; \u0026lt;relativePath/\u0026gt; \u0026lt;!-- lookup parent from repository --\u0026gt; \u0026lt;/parent\u0026gt; \u0026lt;groupId\u0026gt;com.gustavopeiretti\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;springbootdocker\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.0.1-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;name\u0026gt;springbootdocker\u0026lt;/name\u0026gt; \u0026lt;description\u0026gt;Demo project for Spring Boot with Docker\u0026lt;/description\u0026gt; \u0026lt;properties\u0026gt; \u0026lt;java.version\u0026gt;1.8\u0026lt;/java.version\u0026gt; \u0026lt;/properties\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-web\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-test\u0026lt;/artifactId\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;build\u0026gt; \u0026lt;plugins\u0026gt; \u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;com.spotify\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;dockerfile-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.4.13\u0026lt;/version\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;repository\u0026gt;${project.artifactId}\u0026lt;/repository\u0026gt; \u0026lt;buildArgs\u0026gt; \u0026lt;JAR_FILE\u0026gt;target/${project.build.finalName}.jar\u0026lt;/JAR_FILE\u0026gt; \u0026lt;/buildArgs\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;executions\u0026gt; \u0026lt;execution\u0026gt; \u0026lt;id\u0026gt;default\u0026lt;/id\u0026gt; \u0026lt;goals\u0026gt; \u0026lt;goal\u0026gt;build\u0026lt;/goal\u0026gt; \u0026lt;goal\u0026gt;push\u0026lt;/goal\u0026gt; \u0026lt;/goals\u0026gt; \u0026lt;/execution\u0026gt; \u0026lt;/executions\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; \u0026lt;/project\u0026gt; Ejecución de la imagen Docker con Spring Boot usando Maven #Una vez que haya agregado el plugin https://github.com/spotify/dockerfile-maven ejecuta lo siguiente:\nmvnw dockerfile:build docker run -p 5000:8080 springbootdocker Cuando ejecute docker run su aplicación se iniciará para la url localhost url:5000\nUn resumen de los comandos docker que fueron útiles en este post:\ndocker build para crear la imagen docker docker run para ejecutar la imagen docker docker images ver las imágenes docker que tiene disponibles. As always this code can be found by GitHub #https://github.com/gustavopeiretti/spring-boot-examples/tree/master/spring-boot-docker-example\nConclusión #Aprendiste a crear una aplicación Spring Boot Rest, configurar un dockerfile para su aplicación, construir su contenedor Docker y ejecutar su microservicio desde el contenedor. También aprendiste algunos comandos básicos de docker.\n","date":"12 nov 2019","permalink":"https://gustavopeiretti.com/como-crear-un-microservicio-spring-boot-en-docker/","section":"Posts","summary":"\u003cp\u003eAprenderemos cómo ejecutar un microservicio Spring Boot dentro de un contenedor Docker.\u003c/p\u003e","title":"Cómo crear un microservicio con Spring Boot y Docker"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/design-patterns/","section":"Tags","summary":"","title":"Design Patterns"},{"content":"Identificamos algo como un patrón cuando resolvemos un problema que ocurre frecuentemente utilizando un esquema común de solución. Este esquema es posible utilizarlo todas las veces que ocurre el mismo problema, convirtiendo este esquema en un diseño reutilizable.\nEsto ayuda a ahorrar tiempo evitando crear soluciones particulares para algo que ya ha sido resuelto antes.\nUn patrón de diseño es una manera conocida de resolver un problema recurrente.\nEste diseño se convierte así en un template que ya ha sido evaluado innumerables veces por lo que podemos confiar en que han sido validados.\nSin embargo, debemos recordar que estos templates son propuestas para ser utilizadas en nuestros códigos y en algunos casos quizás requieran cambios para adaptarlos, pero la base del template ya nos resume mucho el trabajo.\nUn buen diseño permite un mantenimiento sin mucha dificultad en razón de que es conocido y se encuentra documentado de manera extensiva. Facilita cualquier discusión y análisis que surja sobre el código existente lo que mejora además la lectura para nuevos desarrolladores sobre el código.\nComo se clasifican los patrones de diseño # Hay varios tipos de patrones que pueden resultarnos de gran utilidad. Creacionales, estructurales y de comportamiento. Estos son solo algunos que habitualmente uso y que creo no pueden faltar en nuestra rutina diaria de desarrollo.\nLos creacionales que resuelven problemas en la creación de instancias. # Patrón de diseño Singleton Patrón de Diseño Factory Patrón de Diseño Builder Patrón de diseño Proxy Los estructurales que se resuelven problemas referidos a la estructura de las clases. # Patrón de Diseño Decorator Patrón de Diseño Facade Patrón de Diseño Adapter Patrón de Diseño Composite De comportamiento que resuelven problemas relacionados con la forma en que debe comportarse un objeto. # Patrón de diseño Observer Patrón de diseño Strategy En resumen: # Ayuda a unificar el código desarrollado entre distintos programadores. Ayuda a ganar tiempo en aplicando soluciones conocidas a problemas comunes. Ayuda a crear un código legible y mantenible en el futuro. ","date":"17 jul 2019","permalink":"https://gustavopeiretti.com/patrones-de-diseno-que-debes-conocer/","section":"Posts","summary":"","title":"Patrones de diseño que debes conocer"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/categories/software-design/","section":"Categories","summary":"","title":"Software Design"},{"content":"El patrón de diseño Proxy es simplemente un intermediario que se diseña sobre una clase para agregar alguna funcionalidad adicional, sin modificar la clase original.\nEl patrón Proxy nos dice que construyamos una nueva clase proxy con la misma interfaz que tiene la clase original. Luego en vez de utilizar la clase original, utilizamos la clase proxy en todos los clientes que antes usaban la clase original. La clase proxy agrega la funcionalidad deseada y luego delega todo el trabajo a la clase original.\nPara crear este patrón necesitamos definir una interfaz de la cual extenderá la clase principal. Luego crearemos nuestra clase proxy que también extenderá de la interfaz y tendrá como atributo la clase principal.\nCuales son las partes del patrón de diseño Proxy #Este patrón se conforma principalmente de tres partes.\nInterfaz: de la que se creará la clase principal. Clase principal: que implementa la interfaz. Clase proxy: la clase que también extenderá de la interfaz y que contendrá como atributo la clase principal. Como se crea el patrón de diseño Proxy en Java #Para comprender mejor este patrón veamos un ejemplo. Supongamos que tenemos una clase que realiza procesos para los cuales tiene que leer un archivo grande en disco. Deseamos que esta clase levante el archivo en disco una sola vez, pero no tenemos acceso a modificar la clase original.\nCrearemos a partir de la interfaz nuestra clase. Además de este misma interfaz implementaremos el proxy. El cliente en vez de consultar la clase real, lo hará atraves del proxy.\nTenemos nuestra interfaz de la cual extiende la clase original.\npackage patterns.proxy; public interface BatchProcess { void process(); } La clase que realiza el proceso en el constructor lee el archivo desde el disco. En esta clase simulamos en el método loadFromDisk el trabajo de leer el archivo.\npackage patterns.proxy; public class BatchProcessImpl implements BatchProcess { private final String fileName; public BatchProcessImpl(String fileName) { this.fileName = fileName; loadFromDisk(fileName); } @Override public void process() { System.out.println(\u0026#34;Processing file \u0026#34; + fileName); } private void loadFromDisk(String fileName) { System.out.println(\u0026#34;Expensive and hard process...\u0026#34;); for (int i = 0; i \u0026lt; 10; i++) { System.out.println(\u0026#34;Loading \u0026#34; + fileName + \u0026#34; \u0026#34; + i * 10 + \u0026#34;%\u0026#34;); try { Thread.sleep(1000); } catch (InterruptedException e) { } } System.out.println(\u0026#34;Loaded \u0026#34; + fileName); } } Este proceso de lectura en la clase BatchProcessImpl sabemos que es costoso y quisiéramos que se realice una sola vez. No tenemos acceso a modificar la clase BatchProcessImpl, por lo que decidimos crear una clase proxy. La clase proxy implementa la misma interfaz BatchProcess y tendrá como atributo la clase BatchProcessImpl\npackage patterns.proxy; public class ProxyBatchProcess implements BatchProcess { private BatchProcessImpl batchProcess; private String fileName; public ProxyBatchProcess(String fileName) { this.fileName = fileName; } @Override public void process() { if (batchProcess == null) { batchProcess = new BatchProcessImpl(fileName); } batchProcess.process(); } } Probamos ahora el patrón de diseño Proxy # Creamos el objeto ProxyBatchProcess enviando un archivo grande. Ejecutamos por primera vez y vemos en la salida que el archivo se lee. Luego volvemos a ejecutar y esta vez podemos comprobar que ya no se lee el archivo y solo se realiza el proceso sobre el archivo previamente ‘que fue leído desde el disco’. package patterns.proxy; public class ProxyPatternExample { public static void main(String[] args) { BatchProcess batchProcess = new ProxyBatchProcess(\u0026#34;big_file.txt\u0026#34;); //batchProcess will be loaded from disk System.out.println(\u0026#34;BatchProcess will be loaded from disk\u0026#34;); batchProcess.process(); System.out.println(\u0026#34;-----------------\u0026#34;); //batchProcess will not be loaded from disk System.out.println(\u0026#34;BatchProcess will not be loaded from disk\u0026#34;); batchProcess.process(); } } En la salida vemos que la primer ejecución ‘carga’ el file y en la segunda el proceso se realiza sin volver a ‘cargarlo’ tal como deseábamos.\nBatchProcess will be loaded from disk Expensive and hard process... Loading big_file.txt 0% Loading big_file.txt 10% Loading big_file.txt 20% Loading big_file.txt 30% Loading big_file.txt 40% Loading big_file.txt 50% Loading big_file.txt 60% Loading big_file.txt 70% Loading big_file.txt 80% Loading big_file.txt 90% Loaded big_file.txt Processing file big_file.txt ----------------- BatchProcess will not be loaded from disk Processing file big_file.txt Algunas ventajas y desventajas de este patrón: # Podemos modificar funcionalidad sin afectar a otras funcionalidades que esten usando la clase original directamente. El código se puede volver complicado si es necesario introducir gran cantidad de funcionalidad nueva. La respuesta real del servicio puede ser desconocida hasta que realmente se la invoca. Conclusión: #Hemos visto el patrón Proxy y lo útil que puede resulta para agregar funcionalidad a una clase sin modificarla.\nPuedes descargar este código en GitHub\n","date":"10 jul 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-proxy-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Proxy es simplemente un intermediario que se diseña sobre una clase para agregar alguna funcionalidad adicional, sin modificar la clase original.\u003c/p\u003e","title":"Patrón de diseño Proxy en Java"},{"content":"El patrón de diseño del Observador se usa principalmente cuando estamos interesados en que cualquier cambio de estado sea notificado a quien necesite enterarse de ese cambio.\nEn el patrón de diseño observer el objeto que mira el estado de otro objeto se llama “Observer” y el objeto que está “mirando” esos cambios se denomina \u0026ldquo;Subject\u0026rdquo;.\nJava nos ayuda dándonos herramientas para implementar este patrón de forma simple a través de la clase java.util.Observable y la interfaz java.util.Observer.\nExtendiendo de java.util.Observable definimos nuestra clase que es capaz de ser observada por otras.\nImplementando la interfaz interfaz java.util.Observer creamos nuestra clase que conocer si hay cambios la otra clase Observable.\nCuales son las partes del patrón de diseño Observer #Dijimos que este patrón conforma principalmente de dos partes: una funcionalidad observable y otra que necesita observar los cambios de la primera.\nTenemos en este patrón:\nSubject: es la clase Observable que al cambiar su estado notificará a otras. Observer: es la clase que recibirá la notificación. La clase que quiere conocer sobre los cambios. Como se crea el patrón de diseño Observer en Java #Tal como dijimos previamente necesitamos dos partes. Una clase que permite ser observada y que notificará a otras que la observan . Supongamos tenemos una clase Bank que al ser modificada debe generar ciertos gastos. Deseamos que cualquier cambio de estado en la clase Bank notifique de este cambio a las clases que calcula los gastos.\nLa clase Observable la creamos extendiendo de java.util.Observable. Java hará todo por nosotros con esta clase encargándose de cambiar el estado de esta y notificar a los observadores.\nEn esta clase BankAccount que extiende de Observable tenemos el método addAmount que recibe un monto y luego marca su estado como cambiado y notifica a todos los “observadores” sobre el cambio efectuado.\npackage patterns.observer; import java.util.Observable; public class BankAccount extends Observable { private double balance; public void addAmount(Double amount) { this.balance += amount; setChanged(); notifyObservers(balance); } public Double getBalance() { return balance; } } Luego tenemos nuestra clase que implementa la interfaz Observer y que recibirá la notificación en el método de la interfaz update\nEste método update recibe un value que sabemos es un double que viene de la clase BankAccount (Observable) que la notifica. Luego con ese valor realiza los cálculos que corresponde para calcular la expensa.\npackage patterns.observer; import java.util.Observable; import java.util.Observer; public class BankExpense implements Observer { private String type; private Double totalCalculated = new Double(0D); private final Double rateCoefficient; public BankExpense(String type, Double rateCoefficient) { this.type = type; this.rateCoefficient = rateCoefficient; } @Override public void update(Observable o, Object value) { this.totalCalculated = ((Double) value) * rateCoefficient; } public Double getTotalCalculated() { return totalCalculated; } public String getType() { return type; } @Override public String toString() { return \u0026#34;BankExpense{\u0026#34; + \u0026#34;type=\u0026#39;\u0026#34; + type + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#34;, rateCoefficient=\u0026#34; + rateCoefficient + \u0026#34;, totalCalculated=\u0026#34; + totalCalculated + \u0026#39;}\u0026#39;; } } Probamos ahora el patrón Observer #Creamos el objeto Observable, BankAccount.\nCreamos todas los objetos Observer, BankExpense, que necesitan enterarse de los cambios.\nAgregamos el objeto Observer al Observable usando addObserver.\nCambiamos el estado de la del objeto BankAccount\nVemos el resultado. Todas los objetos BankExpense fueron notificados del cambio.\npackage patterns.observer; public class ObserverPatternExample { public static void main(String[] args) { // Observable class BankAccount bankAccount = new BankAccount(); // Observer class BankExpense bankExpense1 = new BankExpense(\u0026#34;commission\u0026#34;, 0.11d); BankExpense bankExpense2 = new BankExpense(\u0026#34;expense\u0026#34;, 0.22d); BankExpense bankExpense3 = new BankExpense(\u0026#34;compensation\u0026#34;, 0.33d); // Add Observer into Observable bankAccount.addObserver(bankExpense1); bankAccount.addObserver(bankExpense2); bankAccount.addObserver(bankExpense3); // Change Observable state bankAccount.addAmount(1000d); // Observer was notified System.out.println(bankExpense1.toString()); System.out.println(bankExpense2.toString()); System.out.println(bankExpense3.toString()); } } La salida\nBankExpense{type=\u0026#39;commission\u0026#39;, rateCoefficient=0.11, totalCalculated=110.0} BankExpense{type=\u0026#39;expense\u0026#39;, rateCoefficient=0.22, totalCalculated=220.0} BankExpense{type=\u0026#39;compensation\u0026#39;, rateCoefficient=0.33, totalCalculated=330.0} Algunas ventajas y desventajas de este patrón: #El uso de este patrón te permite desacoplar el subjet (Observable) de todos aquellos observadores (Observer) .\nPermite agregar un número ilimitado de Observadores que desean enterarse del cambio.\nHay que tener cuidado con la implementación de los Observer porque podría complicar la performance si son muchos o si está mal implementada.\nConclusión #Hemos visto el patrón Observer y lo fácil que resulta su implementación ayudándonos en los casos en que deseamos que otros objetos sean notificados siempre que se produzca un cambio.\nPuedes descargar este código en\ngithub\n","date":"20 jun 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-observer-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño del Observador se usa principalmente cuando estamos interesados en que cualquier cambio de estado sea notificado a quien necesite enterarse de ese cambio.\u003c/p\u003e\n\u003cp\u003eEn el patrón de diseño observer el objeto que mira el estado de otro objeto se llama “Observer” y el objeto que está “mirando”  esos cambios se denomina \u0026ldquo;Subject\u0026rdquo;.\u003c/p\u003e","title":"Patrón de diseño Observer en Java"},{"content":"El patrón de diseño Facade simplifica la complejidad de un sistema mediante una interfaz mas sencilla. Mejora el acceso a nuestro sistema logrando que otros sistemas o subsistemas usen un punto de acceso en común que reduce la complejidad, minimizando las interacciones y dependencias.\nSe trata de un patrón de diseño bastante útil en vista de que también desacopla los sistemas .\nCuales son las partes del patrón de diseño Facade #Dijimos que el patrón de diseño Facade dispone una interfaz simple y accesible a otros sistemas o subsistemas. De este modo simplifica la complejidad a los clientes externos exponiendo una interfaz más clara y un acceso unificado a estas funcionalidades haciendo más fácil su uso.\nTenemos entonces en este patrón tres partes:\nEl Cliente que accede al facade. El Facade que accede al resto de funcionalidades y las unifica o simplifica. El resto de funcionalidades / subsistemas, que están “detras” del facade. Como se crea el patrón de diseño Facade en Java #Hablamos antes que el objetivo del patrón Facade es simplificar y unificar funcionalidades.\nDe este modo el cliente se olvida de entender la complejidad que hay del otro lado del facade.\nObserva el siguiente ejemplo de un patrón Facade.\nPensemos en un teléfono móvil que debemos encender y para ello es necesario ejecutar varias acciones.\nDefinamos las diferentes funcionalidades de este ejemplo.\npackage patterns.facade; public class Battery { public void on() { System.out.println(\u0026#34;Battery on\u0026#34;); } public void off() { System.out.println(\u0026#34;Battery off\u0026#34;); } } package patterns.facade; public class CPU { public void bootLoad() { System.out.println(\u0026#34;CPU boot loaded\u0026#34;); } public void shutDown() { System.out.println(\u0026#34;CPU shutdown\u0026#34;); } } De esta interfaz MobileService implementaremos los servicios Wifi y GPS\npackage patterns.facade; public interface MobileService { void start(); void close(); } package patterns.facade; public class GPSService implements MobileService { @Override public void start() { System.out.println(\u0026#34;GPS Service started\u0026#34;); } @Override public void close() { System.out.println(\u0026#34;GPS Service closed\u0026#34;); } } package patterns.facade; public class WifiSevice implements MobileService { @Override public void start() { System.out.println(\u0026#34;WIFI Service started\u0026#34;); } @Override public void close() { System.out.println(\u0026#34;WIFI Service started\u0026#34;); } } Nuestra clase que representa el Mobile.\nEl mobile tiene como atributos la bateria, la cpu y los servicios.\npackage patterns.facade; import java.util.List; public class Mobile { private final Battery battery; private final CPU cpu; private final List\u0026lt;MobileService\u0026gt; mobileServices; public Mobile(Battery battery, CPU cpu, List\u0026lt;MobileService\u0026gt; mobileServices) { this.battery = battery; this.cpu = cpu; this.mobileServices = mobileServices; } public CPU getCpu() { return cpu; } public Battery getBattery() { return battery; } public List\u0026lt;MobileService\u0026gt; getMobileServices() { return mobileServices; } } Definamos el facade que se encargará de simplificar todas la operaciones de encendido y de apagado del teléfono móvil.\nObserva que el facade expondrá dos metodos “ON” , “OFF”.\nTodo el resto ocurre dentro de facade y el cliente no necesita entender las acciones ni la secuencia para prender o apagar el teléfono.\npackage patterns.facade; import java.util.Arrays; import java.util.List; public class MobileFacade { public Mobile on() { Battery battery = new Battery(); battery.on(); CPU cpu = new CPU(); cpu.bootLoad(); MobileService gps = new GPSService(); gps.start(); MobileService wifi = new WifiSevice(); wifi.start(); List\u0026lt;MobileService\u0026gt; mobileServices = Arrays.asList(gps, wifi); Mobile mobile = new Mobile(battery, cpu, mobileServices); return mobile; } public void off(Mobile mobile) { for(MobileService service :mobile.getMobileServices()) { service.close(); } mobile.getCpu().shutDown(); mobile.getBattery().off(); } } Probamos el Facade desde nuestro cliente.\npackage patterns.facade; public class ClientFacadePatternExample { public static void main(String[] args) { MobileFacade facade = new MobileFacade(); Mobile mobile = facade.on(); System.out.println(\u0026#34;---------------\u0026#34;); facade.off(mobile); } } La salida\n--------------- ON --------------- Battery on CPU boot loaded GPS Service started WIFI Service started --------------- OFF --------------- GPS Service closed WIFI Service started CPU shutdown Battery off Conclusión #Cómo viste con el ejemplo este patrón es bastante simple de implementar y te ayudará a entregar a los clientes de tu servicio un acceso más sencillo unificando funcionalidades.\nPuedes descargar este código en github\n","date":"3 jun 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-facade-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Facade simplifica la complejidad de un sistema mediante una interfaz mas sencilla.\nMejora el acceso a nuestro sistema logrando que otros sistemas o subsistemas usen un punto de acceso en común que reduce la complejidad, minimizando las interacciones y dependencias.\u003c/p\u003e","title":"Patrón de diseño Facade en Java"},{"content":"El patrón de diseño Builder permite crear objetos que habitualmente son complejos utilizando otro objeto más simple que los construye paso por paso.\nEste patrón Builder se utiliza en situaciones en las que debe construirse un objeto repetidas veces o cuando este objeto tiene gran cantidad de atributos y objetos asociados, y en donde usar constructores para crear el objeto no es una solución cómoda.\nSe trata de un patrón de diseño bastante útil también en la ejecución de test (unit test por ejemplo) en donde debemos crear el objeto con atributos válidos o por defecto.\nNormalmente resuelve el problema sobre decidir qué constructor utilizar. A menudo las clases tienen muchos constructores y es muy difícil mantenerlos. Es común ver constructores múltiples con distintas combinaciones de parámetros.\nCuales son las partes del patrón de diseño Builder #Mencionamos que el patrón de diseño Builder propone crear un objeto completo a partir de otro más simple simplificando la creación del objeto y ayudándonos a obtener un objeto consistente.\nNecesitaremos entonces un objeto Builder que nos creará el objeto que concreto en base a parámetros que le vayamos pasando paso por paso.\nHabitualmente y es buena práctica crear una interfaz con un método build que nos devolverá el objeto que deseamos.\nTenemos entonces en este patrón:\nLa interfaz IBuilder de la cual implementaremos el / los Builder/s.* La implementación de la interfaz builder que implementar el método build y que contiene el resto de métodos que recibirán los parámetros necesarios para construir el objeto final. Como se crea el patrón de diseño Builder en Java #Dijimos que el propósito del patrón Builder es simplificar la creación de objetos que consideramos complejos. Veamos un ejemplo para entender cómo lo resuelve.\nImaginemos un clase que mantiene los datos de una cuenta bancaria.\npackage patterns.builder; public class BankAccount { private long accountNumber; private String owner; private BankAccountType type; private double balance; private double interestRate; public BankAccount() { } public long getAccountNumber() { return accountNumber; } public void setAccountNumber(long accountNumber) { this.accountNumber = accountNumber; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public BankAccountType getType() { return type; } public void setType(BankAccountType type) { this.type = type; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public double getInterestRate() { return interestRate; } public void setInterestRate(double interestRate) { this.interestRate = interestRate; } } La interfaz builder es muy simple, solo necesitas un método build. El uso de la interfaz es opcional. Podrías omitir si deseas y crear directamente el build, pero es buena práctica usar la interfaz.\npackage patterns.builder; public interface IBuilder { BankAccount build(); } Ahora implementas la interfaz y agregas los métodos que irán recibiendo los parámetros. En este ejemplo todos estos métodos que reciben los parámetros para crear el objeto empiezan con “with”. Cada método devuelve el builder.\nEl método builder crea el objeto que se necesita, usando todos los parámetros.\nEs común agregar cualquier campo obligatorio como argumento en el constructor del builder dejando el resto de campos usando los métodos del builder.\nTambién es habitual ver los builder como clases static internas del objeto que se desea crear.\npackage patterns.builder; public class BankAccountBuilder implements IBuilder { private long accountNumber; //This is important, so we will pass it to the constructor. private String owner; private BankAccountType type; private double balance; private double interestRate; public BankAccountBuilder(long accountNumber) { this.accountNumber = accountNumber; } public BankAccountBuilder withOwner(String owner){ this.owner = owner; return this; //By returning the builder each time, we can create a fluent interface. } public BankAccountBuilder withType(BankAccountType type){ this.type = type; return this; } public BankAccountBuilder withBalance(double balance){ this.balance = balance; return this; } public BankAccountBuilder withRate(double interestRate){ this.interestRate = interestRate; return this; } @Override public BankAccount build(){ BankAccount account = new BankAccount(); account.setAccountNumber(this.accountNumber); account.setOwner(this.owner); account.setType(this.type); account.setBalance(this.balance); account.setInterestRate(this.interestRate); return account; } } Probamos ahora el patrón builder. Primero creas el builder new BankAccountBuilder(accountNumber) que por defecto necesita el número de cuenta porque hemos considerado que es un valor indispensable. Luego usamos el builder y vamos enviando los parametros uno por uno.\npackage patterns.builder; public class BuilderPatternExample { public static void main(String[] args) { BankAccountBuilder builder = new BankAccountBuilder(12345l); BankAccount bankAccount = builder.withBalance(1000.20) .withOwner(\u0026#34;Oaken\u0026#34;) .withRate(10.15) .withType(BankAccountType.PLATINUM) .build(); System.out.println(bankAccount); } } La salida\nBankAccount{accountNumber=12345, owner=\u0026#39;Oaken\u0026#39;, type=PLATINUM, balance=1000.2, interestRate=10.15} Algunas ventajas y desventajas de este patrón: # El código resulta más fácil de mantener cuando los objetos tienen mucha cantidad de atributos.* Disminuye los errores al crear el objeto porque el builder especifica paso a paso cómo crearlos y qué atributos necesita.* La mayor desventaja es la necesidad de mantener la duplicidad de de atributos que deben estar en la clase destino y en el builder. Conclusión #Cuando trabajamos con objetos complejos o cuando la complejidad empieza a crecer, el patrón de diseño Builder puede separar esta complejidad usando otro objeto para construir el objeto principal usando un “paso a paso” para tal fin.\nPuedes descargar este código en github\n","date":"28 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-builder-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Builder permite crear objetos que habitualmente son complejos utilizando otro objeto más simple que los construye paso por paso.\u003c/p\u003e","title":"Patrón de diseño Builder en Java"},{"content":"El patrón de diseño Strategy ayuda a definir diferentes comportamientos o funcionalidades que pueden ser cambiadas en tiempo de ejecución.\nEn el patrón Strategy creamos diferentes clases que representan estrategias y que podremos usar según alguna variación o input.\nCuales son las partes del patrón de diseño Strategy #El patrón Strategy está compuesto por una interfaz Strategy de la cual se definen las diferentes clases concretas con la estrategia implementada y el contexto en donde se establece la estrategia a utilizar según alguna condición, regla o input.\nLos componentes del patrón Strategy son:\nInterfaz Strategy: es la interfaz que define cómo se conformará el contrato de la estrategia. Clases Concretas Strategy: son las clases que implementan la interfaz y donde se desarrolla la funcionalidad. Contexto: aquí se decide qué estrategia se usará. Como se crea el patrón de diseño Strategy #Hablamos antes que el objetivo del patrón Strategy es dividir funcionalidades en diferentes estrategias.\nEsto te permite enfocarte en un problema en particular y resolverlo para luego decidir cual es la solución que debe utilizarse para un determinado caso.\nNecesitamos pensar bien cuál será el método o función en común para todas las estrategias que irá en la interfaz. A partir de allí realizas la implementaciones particulares.\nCon un ejemplo se ve más simple. Veamos un ejemplo del patrón Strategy con Java.\nUsaremos un ejemplo muy simple para explicar el patrón Strategy.\nSupongamos esta regla de negocio:\nTenemos diferentes comisiones que se pagan según un monto de venta. Si el monto de venta es mayor se paga mayor comisión.\nDefinimos la interfaz Strategy de la cual crearemos estrategias puntuales para cada caso.\npackage patterns.strategy; public interface CommissionStrategy { double applyCommission(double amount); } Pensamos en las implementaciones de cada Strategy.\nImplementación para un pago de una comisión full.\npackage patterns.strategy; public class FullCommission implements CommissionStrategy { @Override public double applyCommission(double amount) { // do complicated formula of commissions. return amount * 0.50d; } } Implementación para un pago de una comisión normal.\npackage patterns.strategy; public class NormalCommission implements CommissionStrategy { @Override public double applyCommission(double amount) { // do complicated formula of commissions. return amount * 0.30; } } Implementación para un pago de una comisión regular.\npackage patterns.strategy; public class RegularCommision implements CommissionStrategy { @Override public double applyCommission(double amount) { // do complicated formula of commissions. return amount * 0.10; } } Creamos el contexto para las estrategias.\npackage patterns.strategy; public class Context { private CommissionStrategy commissionStrategy; public Context(CommissionStrategy commissionStrategy){ this.commissionStrategy = commissionStrategy; } public double executeStrategy(double amount){ return commissionStrategy.applyCommission(amount); } } Probamos la estrategia con diferentes montos de venta.\npackage patterns.strategy; public class StrategyPatternExample { public static void main(String[] args) { CommissionStrategy commissionStrategy = getStrategy(1000d); Context context = new Context(commissionStrategy); System.out.println(\u0026#34;Commission for 1000d = \u0026#34; + context.executeStrategy(1000d)); commissionStrategy = getStrategy(500d); context = new Context(commissionStrategy); System.out.println(\u0026#34;Commission for 500d = \u0026#34; + context.executeStrategy(500d)); commissionStrategy = getStrategy(100d); context = new Context(commissionStrategy); System.out.println(\u0026#34;Commission for 100d = \u0026#34; + context.executeStrategy(100d)); } private static CommissionStrategy getStrategy(double amount) { CommissionStrategy strategy; if (amount \u0026gt;= 1000d) { strategy = new FullCommission(); } else if (amount \u0026gt;= 500d \u0026amp;\u0026amp; amount \u0026lt;= 999d) { strategy = new NormalCommission(); } else { strategy = new RegularCommision(); } return strategy; } } La salida\nCommission for 1000d = 500.0 Commission for 500d = 150.0 Commission for 100d = 10.0 Que hicimos en el código previo:\nArriba vemos que para una venta de 1000 nuestras reglas de negocio deciden usar la estrategia FullCommission. Del mismo modo para ventas de 500 y 100 se deciden estrategias Normal y Regular respectivamente.\nEl método getStrategy decidirá la estrategia a utilizar según el monto.\nLuego se establecerá esa estrategia en el contexto y se usará para calcular la comisión resultante.\nDecidimos la estrategia que corresponde usar según algún input. Definimos la estrategia en el contexto. Usamos el contexto para determinar el resultado. Conclusión #Vimos cómo crear un patrón Strategy el cual nos ayuda a definir diferentes funcionalidades o algoritmos sobre algún tema común al resolver y elegir el adecuado en tiempo de ejecución.\nPuedes descargar este código en github\n","date":"17 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-strategy-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Strategy ayuda a definir diferentes comportamientos o funcionalidades que pueden ser cambiadas en tiempo de ejecución.\u003c/p\u003e\n\u003cp\u003eEn el patrón Strategy creamos diferentes clases que representan estrategias y que podremos usar según alguna variación o input.\u003c/p\u003e","title":"Patrón de diseño Strategy en Java"},{"content":"El patrón de diseño Adapter te sirve cuando tienes interfaces diferentes o incompatibles entre sí y necesitas que el cliente pueda usar ambas del mismo modo.\nEl patrón de diseño Adapter dice en su definición que convierte una interfaz o clase en otra interfaz que el cliente necesita.\nCuales son las partes del patrón de diseño Adapter #Las partes de patrón Adapter son\nTarget: la interfaz que usamos para crear el adapter. Adapter: es la implementación del target y que se ocupará de realizar la adaptación. Client: es el que interactúa y usa el adapter. Adaptee: es la interfaz incompatible que necesitamos adaptar con el adapter. Como se crea el patrón de diseño Adapter en Java #Mencionamos antes que el patrón tenía varias partes. Un cliente que interactúa con el Adapter para conseguir lo que necesita. El Target de la cual se implementar el Adapter, quien será el encargado de adaptar la respuesta del Adaptee para que el Client la entienda. El Adaptee que representa la clase con una interfaz incompatible para el cliente\nLlevemos esto a un ejemplo en el cual un Cliente necesita información de un servicio BankService que devuelve la información en la clase BankData.\nClient: el cliente necesita información de una cuenta bancaria y la necesita en la clase User. Client: el cliente llama al adapter para conseguir información del User Adapter: el adapter llama al servicio para que devuelva información. Adaptee: el servicio devuelve el BankUser, el Adaptee. Adapter: el adapter convierte BankData en User y la devuelve al client. Client: el cliente recibe la info en User. La clase que si entiende. El servicio que devuelve BankData\npackage patterns.adapter; public class BankService { public BankData findByAccountNumber(int accountNumber) { if (accountNumber == 1) { return new BankData(accountNumber,\u0026#34;Nick\u0026#34;, 100d); } else if (accountNumber == 3) { return new BankData(accountNumber,\u0026#34;Susan\u0026#34;, 200d); } else { return null; } } } La clase BankData con la info\npackage patterns.adapter; public class BankData { private int account; private String name; private double balance; public BankData(int account, String name, double balance) { this.account = account; this.name = name; this.balance = balance; } public String getName() { return name; } public int getAccount() { return account; } public double getBalance() { return balance; } } La clase User que requiere el cliente\npackage patterns.adapter; public class User { private int id; private String name; private double totalAvailable; public User(int id, String name, double totalAvailable) { this.id = id; this.name = name; this.totalAvailable = totalAvailable; } public int getId() { return id; } public String getName() { return name; } public double getTotalAvailable() { return totalAvailable; } } El target (interfaz) de la cual creamos el Adapter\npackage patterns.adapter; public interface UserAdapter { User getUser(int accountNumber); } La implementación del adapter\npackage patterns.adapter; public class UserAdapterImpl implements UserAdapter { private BankService service = new BankService(); @Override public User getUser(int accountNumber) { BankData bankData = service.findByAccountNumber(accountNumber); User user = new User(bankData.getAccount(), bankData.getName(), bankData.getBalance()); return user; } } El client que necesita información en la clase User\npackage patterns.adapter; public class Client { public static void main(String[] args) { UserAdapterImpl adapter = new UserAdapterImpl(); adapter.getUser(1); } } Conclusión #Hemos visto que el patrón Adapter resuelve incompatibilidades entre interfaces adaptando una interfaz hacia la otra utilizando un adapter encargado de la conversión entre interfaces.\nSe trata de un patrón muy utilizado sobre todo cuando nos comunicamos con apis externas y necesitamos adaptar su respuesta hacia nuestras interfaces.\nPuedes descargar este código en github\n","date":"17 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-adapter-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Adapter te sirve cuando tienes interfaces diferentes o incompatibles entre sí y necesitas que el cliente pueda usar ambas del mismo modo.\u003c/p\u003e\n\u003cp\u003eEl patrón de diseño Adapter dice en su definición que convierte una interfaz o clase en otra interfaz que el cliente necesita.\u003c/p\u003e","title":"Patron de Diseño Adapter en Java"},{"content":"El patrón Decorator en Java permite agregar nuevas funcionalidades a las clases sin modificar su estructura.\nEl concepto de este patrón es agregar de forma dinámica nuevo comportamiento o funcionalidades a la clase principal.\nLa definición oficial dice que “permite el ajuste dinámico de objetos para modificar sus responsabilidades y comportamientos existentes.”\nCuales son las partes del patrón de diseño Decorator #El patrón decorador se compone principalmente de una Interfaz de la cual se implementa la clase concreta y los decoradores que añadirá mayor funcionalidad a la clase concreta.\nComponent Interface: es la interface (puede ser una clase abstracta también) que define la funcionalidad y de la cuál se hereda la clase concreta y los decoradores. Concrete Component: es la implementación principal y cuya clase recibirá los decoradores para agregar funcionalidad extra dinámicamente. Decorator: puede ser una clase abstracta o no que define el Decorador que hereda de la interfaz Component y de la cual luego se crearán todos los demás decoradores. El decorador debe mantener la referencia al objeto original a fin de invocarlo y luego agregarle otras funcionalidades propias del decorador. Cada decorador tiene una relación con el componente de tipo HAS-A (tiene un). Concrete Decorator: son las clases que extienden o implementan el Decorator con la funcionalidad acotada. Como se crea el patrón de diseño Decorator en Java #Dijimos que el concepto del patrón decorador es agregar funcionalidades al objeto principal de forma dinámica. Evitando de esta manera la necesidad de crear subclases a la clase principal para agregar funcionalidad.\nLa ventaja es que de este modo no afectamos a todas las clases. Cada clase define una funcionalidad específica que se agrega y decora a la clase principal sin necesidad de crear subclases.\nLo primero que necesitamos buscar es el comportamiento común que tienen todos los objetos y que podría extraerse a una interfaz. Esta interfaz será el contrato que todas las implementaciones, tanto de la clase concreta como la de los decoradores deberá cumplir.\nCon un ejemplo se ve mas simple.\nPensemos en un Reloj al cual se le añaden funcionalidades y según las funcionalidades añadidas se convierte en un reloj deportivo o un reloj de Lujo.\nDefinamos el componente que será la interfaz Watch.\npackage patterns.decorator; public interface Watch { void createFunctionality(); } Ahora creamos la clase concreta BasicWatch a partir de la interfaz\npackage patterns.decorator; public class BasicWatch implements Watch { @Override public void createFunctionality() { System.out.println(\u0026#34; Basic Watch with: \u0026#34;); this.addTimer(); } private void addTimer() { System.out.print(\u0026#34; Timer\u0026#34;); } } Creamos el decorador WatchDecorator también a partir de la interfaz.\npackage patterns.decorator; public abstract class WatchDecorator implements Watch { private final Watch watch; public WatchDecorator(Watch watch) { this.watch = watch; } @Override public void createFunctionality() { this.watch.createFunctionality(); } } Creamos el resto de decoradores a partir del decorador principal que añadirán las funcionalidades particulares.\npackage patterns.decorator; public class SportWatchDecorator extends WatchDecorator { public SportWatchDecorator(Watch watch) { super(watch); } @Override public void createFunctionality(){ super.createFunctionality(); System.out.print(\u0026#34; and more features (Sport Watch): \u0026#34;); this.addPedometer(); this.addSleepMode(); } private void addPedometer() { System.out.print(\u0026#34; Pedometer\u0026#34;); } private void addSleepMode() { System.out.print(\u0026#34; SleepMode \u0026#34;); } } package patterns.decorator; public class LuxuryWatchDecorator extends WatchDecorator { public LuxuryWatchDecorator(Watch watch) { super(watch); } @Override public void createFunctionality() { super.createFunctionality(); System.out.print(\u0026#34; and more features (Luxury Watch): \u0026#34;); this.addFastCharge(); this.addImpermeability(); this.addNFC(); } private void addFastCharge() { System.out.print(\u0026#34; FastCharge \u0026#34;); } private void addImpermeability() { System.out.print(\u0026#34; Impermeability \u0026#34;); } private void addNFC() { System.out.print(\u0026#34; NFC \u0026#34;); } } Bien ahora probemos nuestro patrón decorator.\npackage patterns.decorator; public class ClientDecoratorPattern { public static void main(String... args) { Watch basicWatch = new BasicWatch(); basicWatch.createFunctionality(); System.out.println(\u0026#34;\\n---------\u0026#34;); Watch sportsWatch = new SportWatchDecorator(new BasicWatch()); sportsWatch.createFunctionality(); System.out.println(\u0026#34;\\n---------\u0026#34;); Watch sportsLuxuryWatch = new LuxuryWatchDecorator(new SportWatchDecorator(new BasicWatch())); sportsLuxuryWatch.createFunctionality(); } } Que hicimos en el código previo:\nCreamos nuestro objeto concreto y principal BasicWatch que no tiene mucha funcionalidad más que el timer. Creamos un objeto decorador SportWatchDecorator que añade mayores funcionalidades al al objeto principal BasicWatch Creamos un objeto decorador LuxuryWatchDecorator que añade mayor funcionalidad al decorador SportWatch que a su vez añade funcionalidad al objeto BasicWatch. La salida de esto es\nBasic Watch with: Timer --------- Basic Watch with: Timer and more features (Sport Watch): Pedometer SleepMode --------- Basic Watch with: Timer and more features (Sport Watch): Pedometer SleepMode and more features (Luxury Watch): FastCharge Impermeability NFC Conclusión #Vimos cómo crear un patrón decorator que nos permite agregar nueva funcionalidad en los casos en que extender la clase principal no resulta una buena opción.\nEsta funcionalidad podemos añadirla de forma estática o de forma dinámica según condiciones y nos ayuda a acotar en las clases decorator las características, por lo resulta más simple su implementación.\nPuedes descargar este código en github\n","date":"10 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-decorator-en-java/","section":"Posts","summary":"\u003cp\u003eEl patrón Decorator en Java permite agregar nuevas funcionalidades a las clases sin modificar su estructura.\u003c/p\u003e","title":"Patrón de Diseño Decorator en Java"},{"content":"El patrón de diseño Factory es usado principalmente cuando tenemos una clase o interfaz con muchas subclases o implementaciones y según algún input necesitamos devolver una de estas subclases concretas.\nCuando crear una Factory class #Pensemos en una interfaz de la cual realizamos luego varias implementaciones. Usemos la típica interfaz de ejemplo Shape de la cual implementamos varias clases Circle, Rectangle, Square.\npackage patterns.factory; public interface Shape { void draw(); } package patterns.factory; public class Circle implements Shape { @Override public void draw() { System.out.println(\u0026#34;I am a Circle\u0026#34;); } } package patterns.factory; public class Rectangle implements Shape { @Override public void draw() { System.out.println(\u0026#34;I am a Rectangle\u0026#34;); } } package patterns.factory; public class Square implements Shape { @Override public void draw() { System.out.println(\u0026#34;I am a Square\u0026#34;); } } En este caso tenemos varias implementaciones y según el tipo de Shape que deseamos queremos crear la implementación concreta de la interfaz.\nLa forma habitual (sin un factory) sería de este modo.\npackage patterns.factory; public class FactoryPatternExample { public static void main(String[] args) { FactoryPatternExample example = new FactoryPatternExample(); example.printShape(\u0026#34;CIRCLE\u0026#34;); } // Whithout factory public void printShape(String shapeType) { Shape shape; switch (shapeType) { case \u0026#34;CIRCLE\u0026#34;: shape = new Circle(); break; case \u0026#34;RECTANGLE\u0026#34;: shape = new Rectangle(); break; case \u0026#34;SQUARE\u0026#34;: shape = new Square(); break; default: throw new IllegalStateException(\u0026#34;Unexpected value: \u0026#34; + shapeType); } shape.draw(); } } Como crear una Factory class #Vemos en el ejemplo previo que podríamos simplificar la creación de la clase llevándonos todo lo que esta en el switch a otra clase Factory que se encargue de esto, dejando así nuestro código más simple y claro.\nVamos a crear una clase ShapeFactory para tal fin.\npackage patterns.factory; public class ShapeFactory { public static Shape getShape(String shapeType) { if (shapeType == null) { return null; } if (shapeType.equalsIgnoreCase(\u0026#34;CIRCLE\u0026#34;)) { return new Circle(); } else if (shapeType.equalsIgnoreCase(\u0026#34;RECTANGLE\u0026#34;)) { return new Rectangle(); } else if (shapeType.equalsIgnoreCase(\u0026#34;SQUARE\u0026#34;)) { return new Square(); } else { throw new IllegalStateException(\u0026#34;Unexpected value: \u0026#34; + shapeType); } } } Veamos cómo queda ahora nuestro ejemplo previo haciendo uso de nuestra Factory.\nObserva que queda mucho más limpio y claro delegando la creación de las instancias a la Factory.\nLa Factory será ahora la encargada de crear la instancia en particular y nuestra clase main de ejemplo hará uso de esta factory olvidandose de la complejidad para crearla.\npackage patterns.factory; public class FactoryPatternExample { public static void main(String[] args) { FactoryPatternExample example = new FactoryPatternExample(); example.printShape(\u0026#34;CIRCLE\u0026#34;); } // Using Factory public void printShape(String shapeType) { Shape shape2 = ShapeFactory.getShape(shapeType); shape2.draw(); } } Obviamente este es un ejemplo muy sencillo, en general las Factory class pueden ser más complejas encargándose de crear las instancias bajo condiciones de negocio o diversos inputs que hacen que su uso sea conveniente.\nPuedes descargar este código en github\n","date":"3 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-java-factory/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Factory es usado principalmente cuando tenemos una clase o interfaz con muchas subclases o implementaciones y según algún input necesitamos devolver una de estas subclases concretas.\u003c/p\u003e","title":"Patrón de diseño Factory en Java"},{"content":"El objetivo es que una clase sólo tenga una instancia viva y garantizar que esto suceda.\nEl patrón de diseño Singleton tiene muchas formas de implementarse pero veremos aqui la base de sus implementación que consiste en:\nDejar el constructor de la clase privado evitando que se pueda usar new Crear una variable static en la clase que guardará la instancia de dicha clase. Crear un método público que nos devolverá siempre la misma instancia de la clase que hemos guardado en la variable. Qué es un patrón de diseño Singleton #Normalmente cuando creamos un objeto en Java usamos el keyword new.\nEsto lo que hace es crear una nuevo Objeto cada vez que se lo requiera. SIn embargo, existen ocasiones en las que no deseamos crear un nuevo objeto, al contrario, deseamos ‘compartir’ el objeto.\nEL patrón de diseño singleton nos asegura que solo un objeto sea creado y que solo exista una sola instancia del objeto para la clase.\nCada vez que necesitemos el objeto obtendremos la misma instancia.\nCómo se implementa el patrón Singleton #Hay varias maneras para implementar el patrón Singleton. Veamos cada una.\nImplementación Básica Singleton Pattern #Esta es la forma básica que tendría una clase Singleton. En donde hacemos privado el constructor para evitar su creación con new y definimos un método que nos devuelve siempre la misma instancia.\npackage patterns; public class SingletonExample { private static SingletonExample instance = new SingletonExample(); private SingletonExample() { } static SingletonExample getInstance() { return instance; } } Implementación Singleton Perezosa (Lazy initialization) #Bien, si vemos la implementación previa podemos pensar que estamos creando una instancia siempre, instance = new SingletonExample(), aunque no sea requerida. Podemos pensar en otra implementación en la que realmente se cree el objeto cuando se lo requiera.\nPara esto la variable permanece nula y la inicializamos la primera vez que se invoque el método getInstance() .\nPara prevenir que dos hilos ingresen en simultáneo la primera vez sincronizamos la creación de la instancia.\npackage patterns; public class SingletonExample2 { private static SingletonExample2 instance; private SingletonExample2() { } static SingletonExample2 getInstance() { if (instance == null) { synchronized (SingletonExample2.class) { if (instance == null) { instance = new SingletonExample2(); } } } return instance; } } En este artículo viste las dos formas más simples de crear un Singleton que no pueden faltar cuando te pregunten al respecto.\nPuedes descargar este código en github\n","date":"3 may 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-java-singleton/","section":"Posts","summary":"\u003cp\u003eEl objetivo es que una clase sólo tenga una instancia viva y garantizar que esto suceda.\u003c/p\u003e","title":"Patrón de diseño Singleton en Java"},{"content":"El patrón de diseño Composite permite crear objetos a partir de una interfaz haciendo que todos sean similares y permitiendo que todos sean tratados de la misma manera.\nCuales son las partes del patrón de diseño Composite #Veamos las partes de este patrón Composite:\nComponente (Composite): es la interfaz o clase abstracta de la cual se implementan las clases. Hoja (Leaf): es el objeto que fue implementado a partir del componente. Composición: componente con hijos / hojas. Cliente: es la clase que maneja el composite a través de la interfaz de Componente. Piensa en este componente como en una estructura de árbol de este modo.\nObserva que una composición puede componerse de otras composiciones o simplemente de un solo hijo u hoja. Todas, tanto las composiciones como las hojas pueden ser tratadas de la misma manera a través de su interfaz.\nComo se crea el patrón de diseño Composite en Java #Un ejemplo simple de uso común para comprender mejor este patrón es el ejemplo típico de Empleados y Subordinados con sus diferentes roles dentro.\nAquí tenemos un ejemplo de un Composite Employee del cual se crean un Manager y Developer. Un Manager maneja varios developers que dependen de él.\nDefinamos nuestra interfaz de la cual implementaremos luego otros componentes.\npackage patterns.composite; import java.util.List; public interface Employee { String getName(); void add(Employee e); void remove(Employee e); List\u0026lt;Employee\u0026gt; getEmployees(); int calculatePoints(); } Ahora definimos el componente Manager que implementa la interfaz.\nUn manager es un composite que tiene una lista de developers a cargo.\nAmbas clases, Manager y Developer implementan la interfaz Employee.\npackage patterns.composite; import java.util.ArrayList; import java.util.List; public class Manager implements Employee { private List\u0026lt;Employee\u0026gt; employees = new ArrayList\u0026lt;\u0026gt;(); private String name; public Manager(String name) { this.name = name; } @Override public List\u0026lt;Employee\u0026gt; getEmployees() { return this.employees; } @Override public void add(Employee e) { if (e != null) { this.employees.add(e); } } @Override public void remove(Employee e) { if (e != null) { this.employees.remove(e); } } @Override public int calculatePoints() { if (this.employees.isEmpty()) { return 0; } return Math.round(this.employees.stream().mapToInt(e -\u0026gt; { System.out.println(e); return e.calculatePoints(); }).sum()); } @Override public String getName() { return this.name; } } Definamos la clase Developer que también implementa la interfaz Employee.\nObserva que un manager puede estar compuesto por otros employee, en este caso developers.\nUn developer, suponemos en este ejemplo, que no puede tener otros employee a cargo; por lo que los métodos para agregar elementos a la lista no tienen funcionalidad.\npackage patterns.composite; import java.util.List; import java.util.Random; public class Developer implements Employee { String name; public Developer(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public void add(Employee e) { // nothing to implement } @Override public void remove(Employee e) { // nothing to implement } @Override public List\u0026lt;Employee\u0026gt; getEmployees() { // nothing to implement return null; } @Override public int calculatePoints() { return new Random().nextInt(24); } @Override public String toString() { return \u0026#34;I am \u0026#34; + getName() + \u0026#34;, Developer\u0026#34;; } } Probando el el composite con el cliente. #Definimos la clase ClientComposite que hará uso del componente Employee.\npackage patterns.composite; public class ClientComposite { public static void main(String... args) { Employee m1 = new Manager(\u0026#34;Marc\u0026#34;); Employee d1 = new Developer(\u0026#34;Maria\u0026#34;); Employee d2 = new Developer(\u0026#34;Ema\u0026#34;); Employee d3 = new Developer(\u0026#34;Brian\u0026#34;); m1.add(d1); m1.add(d2); m1.add(d3); Employee m2 = new Manager(\u0026#34;Susan\u0026#34;); Employee d4 = new Developer(\u0026#34;James\u0026#34;); Employee d5 = new Developer(\u0026#34;Michael\u0026#34;); m2.add(d4); m2.add(d5); } } I am Maria, Developer I am Ema, Developer I am Brian, Developer 19 I am James, Developer I am Michael, Developer 20 Conclusión: #Vimos que el patrón composite nos sirve para representar jerarquías y para unificar las operaciones entre los objetos y los objetos individuales a fin de tratarlos a todos de la misma manera simplificando su uso.\nLa desventaja de este patrón composite es que que muchas veces debes definir métodos generales cuya implementación estarán vacíos en algunos casos, tal el caso de la clase developer que vimos.\nPuedes descargar este código aquí #github\n","date":"29 abr 2019","permalink":"https://gustavopeiretti.com/patron-de-diseno-java-composite/","section":"Posts","summary":"\u003cp\u003eEl patrón de diseño Composite permite crear objetos a partir de una interfaz haciendo que todos sean similares y permitiendo que todos sean tratados de la misma manera.\u003c/p\u003e","title":"Patrón de diseño Composite en Java"},{"content":"Vamos a examinar cómo cambiar el time zone de un date en java de distintos modos.\nComo cambiar el timezone de un java.util.Date usando SimpleDateFormat #Debemos tener claro que la clase Date en Java no tiene time zone.\njava.util.Date representa la cantidad de segundos transcurridos desde la medianoche 1 de enero de 1970 a las cero horas (hora UTC).\nEsto significa que siempre el java.util.Date nos devolverá la hora para el time zone que este por default definida para el sistema.\nLo que necesitas hacer para cambiar el time zone a un Date es:\nCrear un DateFormat con el time zone para la zona que queremos Aplicar el DateFormat al Date obteniendo un string con modificado Volver a crear un object Date a partir de ese string import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class TimeZoneChangeDateExample { private static final String DATE_FORMAT = \u0026#34;dd-MM-yyyy hh:mm:ss a\u0026#34;; public static void main(String[] args) throws ParseException { // the date Calendar cal = Calendar.getInstance(); cal.set(2017, 06, 29, 8, 30); Date date = cal.getTime(); // format with tz TimeZone timeZone = TimeZone.getTimeZone(\u0026#34;Europe/Amsterdam\u0026#34;); SimpleDateFormat formatterWithTimeZone = new SimpleDateFormat(DATE_FORMAT); formatterWithTimeZone.setTimeZone(timeZone); // change tz using formatter String sDate = formatterWithTimeZone.format(date); // string to object date SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT); Date dateWithTimeZone = formatter.parse(sDate); // string to Date Object System.out.println(\u0026#34;The actual date is: \u0026#34; + formatter.format(date)); System.out.println(\u0026#34;The date in \u0026#34; + timeZone.getID() + \u0026#34; is: \u0026#34; + sDate); System.out.println(\u0026#34;Object date: \u0026#34; + formatter.format(dateWithTimeZone)); } } La salida de este ejemplo:\nThe actual date is: 29-07-2017 08:30:54 AM The date in Europe/Amsterdam is: 29-07-2017 01:30:54 PM Object date: 29-07-2017 01:30:54 PM Como cambiar el timezone de un Date usando Calendar #Para cambiar el time zone usando calendar debes:\nCrear un calendar Setear el time zone al calendar Obtener los valores a través de los gets especificos. Nota: si intentas obtener el Date directamente, calendar.getTime(), obtendrás la fecha siempre pasada al tiempo local porque lo que devuelve es un java.util.Date y como dijimos antes este no tiene el time zone.\nimport java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.TimeZone; public class TimeZoneChangeCalendarExample { private static final String DATE_FORMAT = \u0026#34;dd-MM-yyyy hh:mm:ss a\u0026#34;; public static void main(String[] args) throws ParseException { // calendar with tx TimeZone timeZone = TimeZone.getTimeZone(\u0026#34;Europe/Amsterdam\u0026#34;); Calendar calendar = Calendar.getInstance(); calendar.set(2017, 06, 29, 8, 30); calendar.setTimeZone(timeZone); // get calendar using fields int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT); System.out.println(\u0026#34;The actual date is: \u0026#34; + formatter.format(calendar.getTime())); System.out.print(\u0026#34;The date in \u0026#34; + timeZone.getID() + \u0026#34; is: \u0026#34;); System.out.print(\u0026#34; Day:\u0026#34; + dayOfMonth); System.out.print(\u0026#34; Month:\u0026#34; + (month + 1)); // base zero System.out.print(\u0026#34; Year:\u0026#34; + year); System.out.print(\u0026#34; Hour:\u0026#34; + hourOfDay); System.out.print(\u0026#34; Min:\u0026#34; + minute); System.out.print(\u0026#34; Sec:\u0026#34; + second); System.out.println(); // calendar getTime with DateFormat SimpleDateFormat formatterWithTimeZone = new SimpleDateFormat(DATE_FORMAT); formatterWithTimeZone.setTimeZone(timeZone); System.out.println(\u0026#34;Calendar.getTime() - Date in Local TZ:\u0026#34; + formatterWithTimeZone.format(calendar.getTime())); } } La salida de este ejemplo:\nThe actual date is: 29-07-2017 03:30:22 AM The date in Europe/Amsterdam is: Day:29 Month:7 Year:2017 Hour:8 Min:30 Sec:22 Calendar.getTime() - Date in Local TZ:29-07-2017 08:30:22 AM Como cambiar el timezone de un Date usando Java 8 en adelante #Para cambiar el time zone de una fecha en Java 8+:\nCrear un LocalDateTime Setear el time zone original al LocalDateTime Cambiar el time zone de la fecha original import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; public class TimeZoneChangeZonedDateTime { public static void main(String[] args) { LocalDateTime localDateTime = LocalDateTime.of(2018, 06, 29, 8, 30); // zone from Buenos Aires ZoneId zoneBuenosAires = ZoneId.of(\u0026#34;America/Buenos_Aires\u0026#34;); ZonedDateTime asiaZonedDateTime = localDateTime.atZone(zoneBuenosAires); // zone from Amsterdan ZoneId zoneAmsterdan = ZoneId.of(\u0026#34;Europe/Amsterdam\u0026#34;); ZonedDateTime nyDateTime = asiaZonedDateTime.withZoneSameInstant(zoneAmsterdan); // print dateTime with tz System.out.println(\u0026#34;Date : \u0026#34; + asiaZonedDateTime); System.out.println(\u0026#34;Date : \u0026#34; + nyDateTime); } } La salida de este ejemplo:\nDate : 2018-06-29T08:30-03:00[America/Buenos_Aires] Date : 2018-06-29T13:30+02:00[Europe/Amsterdam] Puedes visitar este post con mayor detalle sobre la nueva api java.time\nConclusión #Este post muestra tres formas de cambiar el time zone para una fecha, partiendo sobre cómo cambiar el time zone para un java.util.Date, luego para un java.util.Calendar y por último en Java8+ haciendo uso de la nueva api java.time.\nPuedes ver y descargar este código aquí ","date":"29 jun 2018","permalink":"https://gustavopeiretti.com/java-cambiar-time-zone-date/","section":"Posts","summary":"\u003cp\u003eVamos a examinar cómo cambiar el time zone de un date en java de distintos modos.\u003c/p\u003e","title":"Java como cambiar el time zone a un Date"},{"content":"En este articulo veras como convertir un list a un map utilizando para ello un Stream disponible desde Java 8.\n¿Cómo convertir un List a un Map? #Partiendo de una lista de productos creamos un Stream\npublic class Product { private long id; private String name; private String type; private Double price; public Product() { } public Product(long id, String name, String type, double price) { this.id = id; this.name = name; this.type = type; this.price = price; } //... @Override public String toString() { return \u0026#34;Product{\u0026#34; + \u0026#34;id=\u0026#34; + id + \u0026#34;, name=\u0026#39;\u0026#34; + name + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#34;, type=\u0026#39;\u0026#34; + type + \u0026#39;\\\u0026#39;\u0026#39; + \u0026#34;, price=\u0026#34; + price + \u0026#39;}\u0026#39;; } } Creamos un Stream a partir de la lista de productos:\nList\u0026lt;Product\u0026gt; productList = new ArrayList\u0026lt;\u0026gt;(); productList.add(new Product(1, \u0026#34;SONY\u0026#34;, \u0026#34;TV\u0026#34;, 100)); productList.add(new Product(2, \u0026#34;SAMSUNG\u0026#34;, \u0026#34;MOBILE\u0026#34;, 200)); Stream\u0026lt;Product\u0026gt; productStream = productList.stream(); Usar Collectors.toMap para crear un map #Luego haces uso del Stream y “Collectors.toMap” en donde para este ejemplo usamos el id del producto como key del mapa y el nombre como valor.\n// Stream to Map with Collectors.toMap Map\u0026lt;Long, String\u0026gt; productMap = productStream.collect(Collectors.toMap(Product::getId, Product::getName)); productMap.forEach((k,v)-\u0026gt;System.out.println(\u0026#34;key : \u0026#34; + k + \u0026#34; value : \u0026#34; + v)); // output: // key : 1 value : SONY // key : 2 value : SAMSUNG // key : 3 value : LG Usar Function.identity() para guardar el objeto en el value del mapa #Si deseas usar como valor el mismo objeto puedes hacer uso de Function.identity() para el value\nMap\u0026lt;Long, Product\u0026gt; productMapObject = productList.stream().collect(Collectors.toMap(Product::getId, Function.identity())); // output // key : 1 value : Product{id=1, name=\u0026#39;SONY\u0026#39;, type=\u0026#39;TV\u0026#39;, price=100.0} // key : 2 value : Product{id=2, name=\u0026#39;SAMSUNG\u0026#39;, type=\u0026#39;MOBILE\u0026#39;, price=200.0} // key : 3 value : Product{id=3, name=\u0026#39;LG\u0026#39;, type=\u0026#39;MOBILE\u0026#39;, price=300.0} Evitando Duplicate key #Si en en la lista y por consiguiente en el Stream tienes dos elementos con un mismo id recibirás un IllegalStateException al tratar de crear el mapa.\n// Exception productList.add(new Product(2, \u0026#34;SAMSUNG DUPLICATE\u0026#34;, \u0026#34;MOBILE\u0026#34;, 200)); try { Map\u0026lt;Long, String\u0026gt; productMapError = productList.stream().collect(Collectors.toMap(Product::getId, Product::getName)); } catch (IllegalStateException e) { e.printStackTrace(); } El error de salida es confuso porque muestra el valor del mapa en vez de mostrar el key que se duplica.\nException in thread \u0026#34;main\u0026#34; java.lang.IllegalStateException: Duplicate key SAMSUNG //.. Para resolver esto pasas una función que realice el tratamiento de los duplicados para evitar este error:\n// handle duplicate ids Map\u0026lt;Long, String\u0026gt; list = productStream .collect(Collectors.toMap( Product::getId, Product::getName, (oldValue, newValue) -\u0026gt; oldValue )); // output: // key : 1 value : SONY // key : 2 value : SAMSUNG // key : 3 value : LG Básicamente lo que haces es decidir entre los dos valores duplicados con cual deseas quedarte. (oldValue, newValue) -\u0026gt; oldValue\nCreando un mapa ordenado #Para crear un mapa ordenado solo debes indicarle al Stream el ordenamiento que deseas pasándole el comparador que deseas, en este ejemplo ordenamos con el key (id del producto).\n// creating a ordered map Map orderMap = productList.stream() .sorted(Comparator.comparingLong(Product::getId).reversed()) .collect( Collectors.toMap( Product::getId, Product::getName, (oldValue, newValue) -\u0026gt; oldValue, // if duplicate LinkedHashMap::new // use LinkedHashMap to keep order )); orderMap.forEach((k, v) -\u0026gt; System.out.println(\u0026#34;key : \u0026#34; + k + \u0026#34; value : \u0026#34; + v)); // output: // key : 3 value : LG // key : 2 value : SAMSUNG // key : 1 value : SONY Conclusión: usando Stream para colectar el resultado con Collectors.toMap creas un mapa a partir de tu lista.\nLuego puedes evitar duplicados pasándole una función para decidir qué hacer en caso de encontrarse con un key duplicado. .\nMira este código completo en Github # ListToMapStream ","date":"31 may 2018","permalink":"https://gustavopeiretti.com/java-convertir-list-map/","section":"Posts","summary":"\u003cp\u003eEn este articulo veras como convertir un list a un map utilizando para ello un Stream disponible desde Java 8.\u003c/p\u003e","title":"Java Convertir un List a un Map usando Stream"},{"content":"Stream map te permite leer cada elemento y transformar los valores que se encuentran en el Stream entregandote otro\nStream con el resultado para seguir realizando operaciones.\nCómo usar Stream map #Como puedes ver en el ejemplo a continuación map() recibe una función como parámetro para realizar alguna transformación sobre cada elemento y devuelve otro Stream sobre el cual puedes seguir trabajando.\nObserva en el ejemplo a continuación transformamos cada elemento en un String en mayúscula y luego lo colocamos en una nueva lista.\nList\u0026lt;String\u0026gt; fruits = Arrays.asList( \u0026#34;apple\u0026#34;, \u0026#34;banana\u0026#34;, \u0026#34;cherry\u0026#34;, \u0026#34;lemon\u0026#34;, \u0026#34;peach\u0026#34;); List\u0026lt;String\u0026gt; fruitsUpper = fruits.stream().map(String::toUpperCase) .collect(Collectors.toList()); System.out.print(fruitsUpper); // [APPLE, BANANA, CHERRY, LEMON, PEACH] Otro ejemplo en donde el resultado será las tres primeras letras de cada String.\nList\u0026lt;String\u0026gt; fruitsFirstLetters= fruits.stream().map(f -\u0026gt; f.substring(0,3)).collect(Collectors.toList()); System.out.println(fruitsFirstLetters); // [app, ban, che, lem, pea] Podemos realizar transformaciones de objetos en algo distinto, recibiendo en la lambda expresión el objeto como parámetro\ny haciendo algo con él. Por ejemplo, extraer valor de un atributo de un objeto.\nList\u0026lt;User\u0026gt; users = Arrays.asList(new User(\u0026#34;Hamilton\u0026#34;), new User(\u0026#34;Thompson\u0026#34;), new User(\u0026#34;Stallman\u0026#34;), new User(\u0026#34;Torvalds\u0026#34;)); List\u0026lt;String\u0026gt; stringNames = users.stream().map(user -\u0026gt; user.getName()).map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(stringNames); // [HAMILTON, THOMPSON, STALLMAN, TORVALDS] Cómo usar Stream flatMap #Podemos encontrarnos con estructuras algo más complejas. Por ejemplo, una lista con otra lista.\nList\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; programmers = Arrays.asList( Arrays.asList(\u0026#34;Margaret\u0026#34;, \u0026#34;Hamilton\u0026#34;), Arrays.asList(\u0026#34;Ken\u0026#34;, \u0026#34;Thompson\u0026#34;), Arrays.asList(\u0026#34;Richard\u0026#34;, \u0026#34;Stallman\u0026#34;), Arrays.asList(\u0026#34;Linus\u0026#34;, \u0026#34;Torvalds\u0026#34;)); Si obtienes un Stream de esta lista obtendrías otro Stream con una lista\nStream\u0026lt;List\u0026lt;String\u0026gt;\u0026gt; streamWithList = programmers.stream(); Con flatMap lo que haces es un “flatten”, aplanar el resultado. Por ejemplo, aquí aplanamos List y nos quedamos con un Stream “plano”.\n{ {\u0026#34;Margaret\u0026#34;,\u0026#34;Hamilton\u0026#34;}, {\u0026#34;Ken\u0026#34;,\u0026#34;Thompson\u0026#34;}, ... } -\u0026gt; flatMap -\u0026gt; {\u0026#34;Margaret\u0026#34;,\u0026#34;Hamilton\u0026#34;,\u0026#34;Ken\u0026#34;,\u0026#34;Thompson\u0026#34;, ...} List\u0026lt;String\u0026gt; flatList = programmers.stream().flatMap(Collection::stream).collect(Collectors.toList()); System.out.println(flatList); // [Margaret, Hamilton, Ken, Thompson, Richard, Stallman, Linus, Torvalds] Cómo usar Stream filter #Filter aplica un predicado sobre cada elemento y si cumple la condición lo agrega a un nuevo Stream.\nAquí transformas un Stream en otro nuevo Stream con solo elementos que empiezan con “b”\nStream\u0026lt;String\u0026gt; streamWithB = fruits.stream().filter(f -\u0026gt; f.startsWith(\u0026#34;b\u0026#34;)); List\u0026lt;String\u0026gt; listWithB = streamWithB.collect(Collectors.toList()); System.out.println(listWithB); // [banana] Conclusión #Has visto cómo crear un Stream y transformar cada dato del Stream en algo distinto usando map.\nTambién cómo aplanar un Stream complejo para obtener un Stream plano y sobre él seguir realizando operaciones.\nPor último, cómo filtrar resultados aplicando un predicado para los elementos que cumplan con tu condición.\nPuedes ver este código en github y gitlab\ngithub\n","date":"19 mar 2018","permalink":"https://gustavopeiretti.com/java-8-stream-map-flatmap-filter/","section":"Posts","summary":"\u003cp\u003eStream map te permite leer cada elemento y transformar los valores que se encuentran en el \u003ca href=\"/java-8-uso-stream-basico/\"\u003eStream\u003c/a\u003e entregandote otro\u003c/p\u003e\n\u003cp\u003eStream con el resultado para seguir realizando operaciones.\u003c/p\u003e","title":"Java 8 Stream map flatMap y filter"},{"content":"El acceso a variables dentro de lambdas puede ser algo confuso, pero es sencillo si lo ves con un ejemplo.\nObserva este código en el cual accedemos a los parámetros “text” y “count” desde la expresión lambda.\npublic static void showText(String text, int count) { Runnable r = () -\u0026gt; { for (int i = 0; i \u0026lt; count; i++) { System.out.println(text); } }; new Thread(r).start(); } Cuando llamamos al método showText este ejecutará un nuevo hilo con la expresión lambda y retornará de inmediato. ¿Cómo es que estas variables no se pierden dentro de la expresión lambda? Decimos que la expresión lambda ha capturado estos valores de las variables.\nEstas variables son llamadas variables libres porque no son parámetros de la expresión lambda en sí misma y no están tampoco definidas dentro del código lambda.\nUna expresión lambda tiene tres ingredientes:\nEl bloque de código Parámetros Valores de variables libres. Restricciones sobre variables en Lambdas #El valor de estas variables libres puede ser capturado por la lambda expresión pero tienen la restricción de que estás variables NO pueden ser modificadas dentro de la expresión lambda.\nEn nuestro ejemplo no podríamos modificar el valor de la variable “count”. Piensa que si diferentes trabajos ejecutan este código de forma concurrente estarían todos modificando esta contador “count”. Debemos asegurar la expresión lambda siempre “threadsafe”.\npublic static void showText_notWork(String text, int count) { Runnable r = () -\u0026gt; { while (count \u0026gt; 0) { System.out.println(text + \u0026#34; \u0026#34; + count); count--; // Error. Can\u0026#39;t change !! } }; new Thread(r).start(); } Dijimos que NO podemos modificar una variable compartida pero observa que si podemos modificar el valor dentro de un objeto compartido. No tendremos problemas de compilación pero nuestro código no será threadsafe por lo que el resultado puede ser impredecible si múltiples ejecuciones ocurren de forma concurrente.\nEn este ejemplo la asignación de la variable “data” nunca la estamos cambiando pero si estamos modificando su contenido.\npublic static void repeatMessage_noThreadSafe() { List\u0026lt;String\u0026gt; data = new ArrayList\u0026lt;\u0026gt;(); data.add(\u0026#34;file1\u0026#34;); // more into data... for (String p : data) { new Thread(() -\u0026gt; { if (p.startsWith(\u0026#34;file9\u0026#34;)) { data.add(\u0026#34;xfile9\u0026#34;); // changing shared object } }).start(); } } Conclusión: #Vimos una breve explicación sobre el scope de las variables en expresiones lambda y porqué no es posible modificarlas.\nCódigo de ejemplo:\n/j8/variableScope\n","date":"12 mar 2018","permalink":"https://gustavopeiretti.com/java-variable-scope-lambda/","section":"Posts","summary":"\u003cp\u003eEl acceso a variables dentro de \u003ca href=\"/java-8-usar-expresiones-lambda/\"\u003elambdas\u003c/a\u003e puede ser algo confuso, pero es sencillo si lo ves con un ejemplo.\u003c/p\u003e","title":"Java 8 Variable Scope en Lambda"},{"content":"En Java 8 se han introducido importantes cambios como lambdas, interfaces funcionales y métodos por referencia.\nVeamos ahora cómo hacer uso de constructores por referencia.\nSi no has leido el articulo sobre métodos por referencia te recomiendo que le des un vistazo porque tiene mucho en común con el artículo a continuación. La diferencia es que aquí llamas al “new” en vez de llamar a un método.\nPartamos de un ejemplo para que se vea claramente.\nTenemos este User con tres constructores, uno por default, otro que recibe el “name” y el último que recibe “name” y “password”. Deseamos crear varios user partiendo de una lista de nombres.\npublic class User { private String name; private String password; public User() { } public User(String name) { this.name = name; } public User(String name, String pass) { this.name = name; this.password = pass; } } La lista de nombres predefinidos que queremos utilizar para crear los User.\nList\u0026lt;String\u0026gt; userNames = new ArrayList\u0026lt;\u0026gt;(); userNames.add(\u0026#34;jose\u0026#34;); userNames.add(\u0026#34;luis\u0026#34;); userNames.add(\u0026#34;lucas\u0026#34;); Como llamar al constructor por referencia #Para este ejemplo nos valdremos de stream().map() que nos permite convertir un objeto en algo diferente. En nuestro “mapeamos” un String en un User.\nLuego usaremos stream.collect para recoger todos los elementos en una lista de Users.\nPor último los iteramos para mostrar el resultado.\nLo importante aquí es observar que estamos llamando al constructor por referencia cuando escribimos User::new.\n¿Pero cuál constructor llamará .map(..) si tenemos varios constructores en la clase User.\nAquí el compilador elige por inferencia el constructor que tenga un solo parámetro String porque es el único que aplica.\nStream\u0026lt;User\u0026gt; userStream = userNames.stream().map(User::new); List\u0026lt;User\u0026gt; userList = userStream.collect(Collectors.toList()); userList.forEach(System.out::println); //.. output.. User{name=\u0026#39;jose\u0026#39;} User{name=\u0026#39;luis\u0026#39;} User{name=\u0026#39;lucas\u0026#39;} …\nEn conclusión vemos que así como usamos métodos por referencia tambien podemos hacerlo para constructores del modo User::new.\nAdemás el compilador elige el constructor correspondiente por inferencia.\nCódigo de ejemplo:\nj8/constructReference\nReferencias: Lambdas Interfaces funcionales Métodos por referencia\n","date":"8 mar 2018","permalink":"https://gustavopeiretti.com/java-8-constructor-referencia/","section":"Posts","summary":"\u003cp\u003eEn Java 8 se han introducido importantes cambios como lambdas, interfaces funcionales y métodos por referencia.\u003c/p\u003e\n\u003cp\u003eVeamos ahora cómo hacer uso de constructores por referencia.\u003c/p\u003e","title":"Java 8 Constructor por Referencia"},{"content":"Java 8 introduce Optional, este es un wrapper que nos ayuda a prevenir los nullpointer tan comunes en Java. Optional nos da un métodos adecuados para validar si el valor contenido esta null o no.\nEvitar los Nullpointer es uno de los problemas con los que habitualmente nos encontramos los programadores en Java. Continuamente realizamos operaciones para verificar que el valor no sea null o tener la precaución de devolver valores not null y a pesar de esto es habitual el fallo por los null pointer.\nComo crear un Optional para un objeto #La forma correcta de crear un Optional para un objeto no nulo es la siguiente.\nUser user = new User(\u0026#34;gustavo\u0026#34;); Optional\u0026lt;User\u0026gt; optUser = Optional.of(user); Si utilizas Optional.of con un valor null obtendras un nullpointer inmediatamente en el metodo of.\nEsto resulta en la ventaja de no esperar hasta usar el User para encontrarse con la excepción.\nPor ejemplo, aqui tendremos un null pointer en Optional, antes de hacer uso de User nulo.\nUser user = null; Optional\u0026lt;User\u0026gt; optUser = Optional.of(user); // NullPointerException here … user.getName(); // ... Exception in thread \u0026#34;main\u0026#34; java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:203) at java.util.Optional.\u0026lt;init\u0026gt;(Optional.java:96) at java.util.Optional.of(Optional.java:108) at j8.optional.OptionalExample.main(OptionalExample.java:9) Si sabes que el objeto User está null o es posible que este nulo y quieres devolver un Optional debes utilizar el método Optional.ofNullable(..);\nUser user = null; Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); Como utilizar Optional en Java #Dijimos que el uso de Optional es determinar si un objeto está nul o no, aunque es mejor decir que Optional te dirá si el objeto está presente.\nA continuación vas a crear un Optional para un objeto User y vas a determinar si está presente.\n// logic to create User User user = new User(\u0026#34;john\u0026#34;); // Create Optional for User Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); if (optUser.isPresent()) { System.out.println(optUser.get().getName()); } // using j8 lambdas optUser.ifPresent(u -\u0026gt; System.out.println(u.getName())); Tambien puedes utilizar lambdas con el metodo ifPresent(..)\nUser user = new User(\u0026#34;john\u0026#34;); Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); // using j8 lambdas optUser.ifPresent(u -\u0026gt; System.out.println(u.getName())); Como utilizar Optional orElse / orElseGet en Java #Lo que hace orElse es devolver el valor si está presente o el valor que se pasa por parámetro si está ausente. Es decir usa un valor DEFAULT si el objeto no esta presente.\nUser user = null; Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); System.out.println(optUser.orElse(User.EMPTY_USER).getName()); // output // EMPTY_USER En el caso de orElseGet también se devuelve un valor por default si el valor no está presente, solo que aquí el valor se devuelve utilizando la interfaz funcional Supplier.\nLo positivo aquí es que esta función solo será llamada si el valor no esta presente evitando procesamiento. En nuestro ejemplo es bastante simple, pero en los casos en que la ejecución de la función sea costosa este método es recomendable.\n// orElseGet User user = null; Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); System.out.println(optUser.orElseGet(new Supplier\u0026lt;User\u0026gt;() { @Override public User get() { return User.EMPTY_USER; } }).getName()); // better with j8 lambdas ! System.out.println(optUser.orElseGet(() -\u0026gt; User.EMPTY_USER).getName()); Tirando una expection con Optional.orElseThrow #Vimos que usando orElse / orElseGet lo que buscas es devolver otro valor por default si el valor dentro de Optional está ausente. Usando orElseThrow lo que deseas en cambio es tirar una Exception si este valor no está.\n// orElseThrow User nullUser = null; Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(nullUser); optUser.orElseThrow(IllegalArgumentException::new); // output Exception in thread \u0026#34;main\u0026#34; java.lang.IllegalArgumentException at java.util.Optional.orElseThrow(Optional.java:290) at j8.optional.OptionalExample.main(OptionalExample.java:35) Como usar Optional.filter en Java #Optional.filter te permite filtrar elementos que no deseas. Suponiendo que solo deseas imprimir algún resultado para un determinado User, en este ejemplo el User cuyo nombre es “john”.\nUser user = new User(\u0026#34;john\u0026#34;); Optional\u0026lt;User\u0026gt; optUser = Optional.ofNullable(user); // filter + ifPresent optUser.filter(u -\u0026gt; \u0026#34;john\u0026#34;.equals(u.getName())) .ifPresent(u -\u0026gt; System.out.println(u.getName())); // filter + isPresent if (optUser.filter(u -\u0026gt; \u0026#34;john\u0026#34;.equals(u.getName())) .isPresent()) { System.out.println(\u0026#34;john is present\u0026#34;); } Como usar Optional.map y Optional.flatMap #Optional.map transforma o ‘mapea’ un valor en otro devolviendote otro Optional para el tipo de dato.\nPor ejemplo si deseamos obtener un Optional con la edad Integer) del User\nOptional\u0026lt;Integer\u0026gt; userAge = optUser.map(User::getAge); Ahora siendo el valor devuelto con “Optional.map” también otro Optional podemos aplicarle filtros\n// filter + map if(optUser.map(User::getAge).filter(age -\u0026gt; age \u0026gt;= 18).isPresent()) { System.out.print(\u0026#34;The user is older\u0026#34;); } ¿Cuál es la diferencia entre map y flatMap?\nDebes usar map si la función te retorna un objeto, en cambio si la función retorna un Optional usas flatMap\n// filter + flatMap optUser.flatMap(User::getOptionalEmail).ifPresent(email -\u0026gt; sendEmail(email)); private static void sendEmail(String email) { System.out.println(\u0026#34;Sending email to \u0026#34; + email); } Siempre es conveniente utilizar Optional en vez de validar los nulos en la forma tradicional\nOptional nos provee de herramientas para evitar los típicos errores con nulos, aunque es necesario usarlo correctamente porque si no validamos antes que el objeto este presente podemos incurrir facilmente en otro tipo de error.\nSi olvidamos verificar si el objeto está presente y hacemos uso de get directamente tendremos una exception.\nString data = null; Optional\u0026lt;String\u0026gt; opt = Optional.ofNullable(data); opt.get().toString(); Exception in thread \u0026#34;main\u0026#34; java.util.NoSuchElementException: No value present at java.util.Optional.get(Optional.java:135) Optional, además de facilitarnos el control de nulos o no presentes nos provee de funcionalidades como filter, map, orElse, orElseThrow que nos resuelven muchas de las tareas habituales.\nPuedes consultar este ejemplo en github, espero te sirva.\n—\n","date":"26 ene 2018","permalink":"https://gustavopeiretti.com/java-8-optional/","section":"Posts","summary":"\u003cp\u003eJava 8 introduce \u003ca href=\"https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html\" target=\"_blank\" rel=\"noreferrer\"\u003eOptional\u003c/a\u003e, este es un wrapper que nos ayuda a prevenir los nullpointer tan comunes en Java. Optional nos da un métodos adecuados para validar si el valor contenido esta null o no.\u003c/p\u003e","title":"Java 8 Optional"},{"content":"Java 8 nos trae al fin una nueva api para el manejo de fechas. Nos encontramos dentro del paquete java.time con nuevas clases para resolver los problemas con fechas como LocalDate, horas con LocalTime o la combinación de fecha y hora con LocalDateTime. También incluye como es debido dentro de esta api el uso de zonas horarios con ZonedDateTime.\nAdemás los conceptos de Period para determinar el periodo entre dos fechas y Duration para determinar la duración entre dos horas.\nAquí te mostraré pequeños ejemplos para conocer esta api a fin de que luego en el uso ya te encuentres familiarizado con ellas.\nLocalDate #LocalDate representa la fecha sin la hora.\nLocalDate localDate = LocalDate.now(); System.out.println(localDate.toString()); LocalDate localDateOf = LocalDate.of(2017, 10, 10); System.out.println(localDateOf.toString()); // 2017-10-10 Puedes además sumar o restar días facilmente,\nLocalDate datePlus = localDateOf.plusDays(7); System.out.println(datePlus.toString()); // 2017-10-17 LocalDate dateMinus = localDateOf.minusDays(7); System.out.println(dateMinus.toString()); // 2017-10-03 Determinar cuál es fecha esta es anterior o posterior respecto a otra\nboolean isBefore = LocalDate.of(2017, 10, 10) .isBefore(LocalDate.of(2017, 8, 20)); System.out.println(isBefore); // false boolean isAfter = LocalDate.of(2017, 10, 10) .isAfter(LocalDate.of(2017, 8, 20)); System.out.println(isAfter); // true LocalTime #LocalTime es similar a LocalDate en su uso y representa la hora sin la fecha.\nLocalTime localTime = LocalTime.now(); System.out.println(localTime); LocalTime hour = LocalTime.of(6, 30); System.out.println(hour); // 06:30 Sumar o restar horas o cualquier otro tipo de unidad como segundos\nLocalTime localTimePlus = hour.plus(1, ChronoUnit.HOURS); System.out.println(localTimePlus); // 07:30 LocalTime localTimeMinus = hour.minus(60, ChronoUnit.SECONDS); System.out.println(localTimeMinus); // 06:29 También podemos comparar para saber si alguna hora es mayor o no que otra.\nboolean isBeforeHour = LocalTime.parse(\u0026#34;08:30\u0026#34;) .isBefore(LocalTime.parse(\u0026#34;10:20\u0026#34;)); System.out.println(isBeforeHour); // true LocalDateTime #LocalDateTime es la combinación del la fecha y la hora. Al igual que con LocalDate y LocalTime puedes crear instancias\nLocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); LocalDateTime localDateTimeOf = LocalDateTime.of(2017, Month.AUGUST, 20, 8, 30); System.out.println(localDateTimeOf); // 2017-08-20T08:30 Igual que como vimos en LocalDate y LocalTime, puedes sumar o restar facilmente utilizando diferentes unidades de tiempo\nLocalDateTime localDateTimePlus = localDateTimeOf.plusDays(5); System.out.println(localDateTimePlus); // 2017-08-25T08:30 LocalDateTime localDateTimeMinus = localDateTimePlus.minusMinutes(10); System.out.println(localDateTimeMinus); // 2017-08-25T08:20 ZonedDateTime #Si necesitas trabajar con zonas horarias puedes utilizar esta clase que te provee el manejo de fechas con hora para la zona que determines. La lista de zonas disponibles las puedes consultar desde la clase ZoneId\nZoneId.getAvailableZoneIds().forEach(z -\u0026gt; System.out.println(z)); // list of all zones ZoneId zoneId = ZoneId.of(\u0026#34;America/Panama\u0026#34;); Para ‘moverse’ a otra zona horaria, por ejemplo Tokyo, haces uso de de LocalDateTime en conjunto con ZoneDateTime pasando la zona “Asia/Tokyo”\nLocalDateTime localDateTimeOf = LocalDateTime.of(2017, Month.AUGUST, 20, 8, 30); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTimeOf, zoneId); System.out.println(zonedDateTime); // 2017-08-20T08:30-05:00[America/Panama] ZonedDateTime tokyoDateTime = localDateTimeOf.atZone(ZoneId.of(\u0026#34;Asia/Tokyo\u0026#34;)); System.out.println(tokyoDateTime); // 2017-08-20T08:30+09:00[Asia/Tokyo] Period #Con la clase Period puedes obtener la diferencia entre dos fechas o utilizarlo para modificar valores de alguna fecha.\nLocalDate startLocalDate = LocalDate.of(2017, 10, 10); LocalDate endLocalDate = startLocalDate.plus(Period.ofDays(10)); // 2017-10-20 int diffDays = Period.between(startLocalDate, endLocalDate).getDays(); System.out.println(diffDays); // 10 Duration #Duration es el equivalente a Period pero para las horas.\nLocalTime startLocalTime = LocalTime.of(8, 30); LocalTime endLocalTime = startLocalTime.plus(Duration.ofHours(3)); // 11:30 long diffSeconds = Duration.between(startLocalTime, endLocalTime).getSeconds(); System.out.println(diffSeconds); // 10800 seconds Código completo #Te dejo copiado todo el ejemplo completo para tu uso.\nTe recomiendo lo copies y en tu ID para que lo veas más claro. Espero te sirva.\nimport java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.Period; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; public class DateTimeExample { public static void main(String[] args) { // LocalDate localDateExample(); // LocalTime localTimeExample(); // LocalDateTime localDateTimeExample(); // ZonedDateTime zonedDateTimeExample(); // Period periodExample(); // Duration durationExample(); } private static void localDateExample() { LocalDate localDate = LocalDate.now(); System.out.println(localDate.toString()); LocalDate localDateOf = LocalDate.of(2017, 10, 10); System.out.println(localDateOf.toString()); // 2017-10-10 LocalDate datePlus = localDateOf.plusDays(7); System.out.println(datePlus.toString()); // 2017-10-17 LocalDate dateMinus = localDateOf.minusDays(7); System.out.println(dateMinus.toString()); // 2017-10-03 boolean isBefore = LocalDate.of(2017, 10, 10) .isBefore(LocalDate.of(2017, 8, 20)); System.out.println(isBefore); // false boolean isAfter = LocalDate.of(2017, 10, 10) .isAfter(LocalDate.of(2017, 8, 20)); System.out.println(isAfter); // true } private static void localTimeExample() { LocalTime localTime = LocalTime.now(); System.out.println(localTime); LocalTime hour = LocalTime.of(6, 30); System.out.println(hour); // 06:30 LocalTime localTimePlus = hour.plus(1, ChronoUnit.HOURS); System.out.println(localTimePlus); // 07:30 LocalTime localTimeMinus = hour.minus(60, ChronoUnit.SECONDS); System.out.println(localTimeMinus); // 06:29 boolean isBeforeHour = LocalTime.parse(\u0026#34;08:30\u0026#34;) .isBefore(LocalTime.parse(\u0026#34;10:20\u0026#34;)); System.out.println(isBeforeHour); // true } private static void localDateTimeExample() { LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); LocalDateTime localDateTimeOf = LocalDateTime.of(2017, Month.AUGUST, 20, 8, 30); System.out.println(localDateTimeOf); // 2017-08-20T08:30 LocalDateTime localDateTimePlus = localDateTimeOf.plusDays(5); System.out.println(localDateTimePlus); // 2017-08-25T08:30 LocalDateTime localDateTimeMinus = localDateTimePlus.minusMinutes(10); System.out.println(localDateTimeMinus); // 2017-08-25T08:20 } private static void zonedDateTimeExample() { ZoneId.getAvailableZoneIds().forEach(z -\u0026gt; System.out.println(z)); // list of all zones ZoneId zoneId = ZoneId.of(\u0026#34;America/Panama\u0026#34;); LocalDateTime localDateTimeOf = LocalDateTime.of(2017, Month.AUGUST, 20, 8, 30); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTimeOf, zoneId); System.out.println(zonedDateTime); // 2017-08-20T08:30-05:00[America/Panama] ZonedDateTime tokyoDateTime = localDateTimeOf.atZone(ZoneId.of(\u0026#34;Asia/Tokyo\u0026#34;)); System.out.println(tokyoDateTime); // 2017-08-20T08:30+09:00[Asia/Tokyo] } private static void periodExample() { LocalDate startLocalDate = LocalDate.of(2017, 10, 10); LocalDate endLocalDate = startLocalDate.plus(Period.ofDays(10)); // 2017-10-20 int diffDays = Period.between(startLocalDate, endLocalDate).getDays(); System.out.println(diffDays); // 10 } private static void durationExample() { LocalTime startLocalTime = LocalTime.of(8, 30); LocalTime endLocalTime = startLocalTime.plus(Duration.ofHours(3)); // 11:30 long diffSeconds = Duration.between(startLocalTime, endLocalTime).getSeconds(); System.out.println(diffSeconds); // 10800 seconds } } …\n","date":"17 ene 2018","permalink":"https://gustavopeiretti.com/java-8-fechas-horas/","section":"Posts","summary":"\u003cp\u003eJava 8 nos trae al fin una nueva api para el manejo de fechas. Nos encontramos dentro del paquete \u003ca href=\"https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html\" target=\"_blank\" rel=\"noreferrer\"\u003e\u003cstrong\u003ejava.time\u003c/strong\u003e\u003c/a\u003e con nuevas clases para resolver los problemas con fechas como LocalDate, horas con LocalTime o la combinación de fecha y hora con LocalDateTime. También incluye como es debido dentro de esta api el uso de zonas horarios con ZonedDateTime.\u003c/p\u003e","title":"Java 8 como usar fechas y horas con la api java.time"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/concurrency/","section":"Tags","summary":"","title":"Concurrency"},{"content":"ExecutorService nos simplifica las tareas asincronas proveyendo un pool de hilos que son manejados por esta API abstrayendonos del trabajo de crearlos y asignarles tareas a estos hilos.\nUtilizando la factory class Executors #La forma más común para crear una instancia de ExecutorService es a través de la factory class Executors.\nPor ejemplo si deseas crear pool con 10 threads lo puedes hacer de este modo:\nExecutorService executor = Executors.newFixedThreadPool(10); Si quieres crear un pool con un solo hilo en los que las tareas queden en cola y se ejecuten de forma secuencial:\nExecutorService executor = Executors.newSingleThreadExecutor(); Creando instancias directamente #Puedes directamente crear instancias de cualquiera de las implementaciones de ExecutorService, observa que esta es una interfaz con múltiples implementaciones.\nPor ejemplo para crear un pool de 10 hilos del mismo modo que lo hace la factory class Executors.newSingleThreadExecutor().\nExecutorService executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue\u0026lt;Runnable\u0026gt;()); ¿Cómo ejecutar tareas con ExecutorService? #Usando ExecutorService.execute #ExecutorService en su método execute ejecuta cualquier implementacion de Runnable, por lo que su ejecución la haces de este modo:\nRunnable command = new Runnable() { @Override public void run() { doLongWork(); } }; executor.execute(command); Usando lambdas puedes cambiar este código por uno más limpio. Copia este codigo completo y pruebalo localmente.\npackage executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(10); executor.execute(() -\u0026gt; doLongWork(\u0026#34;hi 1\u0026#34;)); executor.execute(() -\u0026gt; doLongWork(\u0026#34;hi 2\u0026#34;)); executor.execute(() -\u0026gt; doLongWork(\u0026#34;hi 3\u0026#34;)); } private static void doLongWork(String hola) { System.out.println(\u0026#34;Running \u0026#34; + hola); try { Thread.sleep(1000l); } catch (InterruptedException e) { e.printStackTrace(); } } } Usando ExecutorService.submit #EjecutorService.execute es un método void por lo que no puedes conocer el resultado, pero ExecutorService puede también retornar el resultado de tu ejecución si utilizas el método submit.\nExecutorService executor = Executors.newFixedThreadPool(10); Future\u0026lt;String\u0026gt; future = executor.submit(() -\u0026gt; doLongWork(\u0026#34;hi with future 1\u0026#34;)); future.get(); Future.get te devuelve el resultado de la ejecución de tu metodo luego de que este ya ha terminado.\nPrueba este ejemplo completo\npackage executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ExecutorServiceFutureExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(10); Future\u0026lt;String\u0026gt; future = executor.submit(() -\u0026gt; doLongWork(\u0026#34;hi with future 1\u0026#34;)); System.out.println(future.get()); } private static String doLongWork(String msg) { System.out.println(\u0026#34;Running \u0026#34; + msg); try { Thread.sleep(1000l); } catch (InterruptedException e) { e.printStackTrace(); } return \u0026#34;done \u0026#34; + msg; } } Usando ExecutorService.invokeAny #ExecutorService.invokeAny recibe una lista de Callable, ejecuta todas las task y devuelve el resultado de una ejecución correcta\nExecutorService executor = Executors.newFixedThreadPool(10); Collection\u0026lt;Callable\u0026lt;String\u0026gt;\u0026gt; callables = new ArrayList\u0026lt;\u0026gt;(); callables.add(() -\u0026gt; doLongWork(\u0026#34;hi! 1\u0026#34;)); callables.add(() -\u0026gt; doLongWork(\u0026#34;hi! 2\u0026#34;)); String oneResult = executor.invokeAny(callables); Usando ExecutorService.invokeAll #ExecutorService.invokeAll recibe una también una lista de Callable, ejecuta todas las task y pero devuelve el resultado de todas las ejecuciones\npackage executor; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ExecutorServiceFutureAnyExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(10); Collection\u0026lt;Callable\u0026lt;String\u0026gt;\u0026gt; callables = new ArrayList\u0026lt;\u0026gt;(); callables.add(() -\u0026gt; doLongWork(\u0026#34;hi! 1\u0026#34;)); callables.add(() -\u0026gt; doLongWork(\u0026#34;hi! 2\u0026#34;)); List\u0026lt;Future\u0026lt;String\u0026gt;\u0026gt; result = executor.invokeAll(callables); for (Future f : result) { System.out.println(\u0026#34;f.isDone : \u0026#34; + f.isDone() + \u0026#34; f.get : \u0026#34; + f.get()); } } private static String doLongWork(String msg) { System.out.println(\u0026#34;Running \u0026#34; + msg); try { Thread.sleep(1000l); } catch (InterruptedException e) { e.printStackTrace(); } return \u0026#34;finish \u0026#34; + msg; } } Como terminar ExecutorService #Por defecto ExecutorService se queda ‘escuchando’ nuevas tareas, se queda vivo para recibir nuevas tareas y asignarlas a su pool. Si deseas finalizarlo para que no reciba nuevas tareas puedes ejecutar su método shutdown() para “solicitarle” la terminación. Una vez terminadas la tareas en ejecución se finalizará el servicio.\nTambién puedes requerir la finalización inmediata usando shutdownNow(), aunque esto último no esta garantizado. Este método te devuelve la lista de tareas que no finalizaron si deseas conocerlas.\nExecutorService executor = Executors.newFixedThreadPool(10); ... List\u0026lt;Runnable\u0026gt; runnableList = executor.shutdownNow(); —\n","date":"11 ene 2018","permalink":"https://gustavopeiretti.com/java-executorservice/","section":"Posts","summary":"\u003cp\u003eExecutorService nos simplifica las tareas asincronas proveyendo un pool de hilos que son manejados por esta API abstrayendonos del trabajo de crearlos y asignarles tareas a estos hilos.\u003c/p\u003e","title":"Java – como usar ExecutorService"},{"content":"Un buen patrón para resolver la complejidad cuando debes implementar diferentes comportamientos según algún estado es el patrón strategy.\nUn patrón strategy encapsula comportamiento que podemos intercambiar en ejecución. Es decir, cambiar el comportamiento o lógica de negocio acorde al estado del modelo o contexto en el que te se encuentra, evitando el uso extensivo de if o switch en tu código.\nEs bastante simple. Necesitas una interfaz Strategy y diferentes implementaciones para la resolución de los diferentes comportamientos deseados.\nPara este ejemplo suponemos que tenemos una entidad “User” que representa un usuario. Estos users son clasificados por tipo acorde a un enum “UserType”. El UserType determinará el valor del atributo limitCredit del User.\n@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @NotBlank private String userName; @NotBlank private String lastName; private UserType type; private double limitCredit; } public enum UserType { NORMAL, FULL, GOLD; } Queremos que nuestro servicio se desentienda de esta decisión, por lo que crearemos diferentes estrategias para cada tipo de user.\nCómo crear el patrón Strategy #Defines la interfaz de la cual luego vas a implementar los diferentes comportamientos. En este ejemplo simple se trata de cambiar el limite bajo algún cálculo que suponemos complejo para los diferentes tipos de User.\npublic interface Strategy { void changeLimit(User user); } Las implementaciones de las estrategias para cada tipo UserType quedan así:\npublic class StrategyOperationNormal implements Strategy { @Override public void changeLimit(User user) { // a complex calculation.. user.setType(UserType.NORMAL); user.setLimitCredit(1000D); } } public class StrategyOperationFull implements Strategy { @Override public void changeLimit(User user) { user.setType(UserType.FULL); user.setLimitCredit(5000D); } } public class StrategyOperationGold implements Strategy { @Override public void changeLimit(User user) { user.setType(UserType.GOLD); user.setLimitCredit(20000D); } } Usar un Factory que nos devuelva el Strategy #Para simplificar aún más el uso de Strategy en tu servicio creas una clase StrategyFactory. Este factory te devolverá la estrategia correspondiente según el UserType.\nUn patrón factory te permite crear objetos bajo alguna condición sin necesidad de conocer o preocuparte acerca de la implementación real, en definitiva solo conoces la interfaz.\n@Component public class StrategyFactory { private Map\u0026lt;UserType, Strategy\u0026gt; strategies = new EnumMap\u0026lt;\u0026gt;(UserType.class); public StrategyFactory() { initStrategies(); } public Strategy getStrategy(UserType userType) { if (userType == null || !strategies.containsKey(userType)) { throw new IllegalArgumentException(\u0026#34;Invalid \u0026#34; + userType); } return strategies.get(userType); } private void initStrategies() { strategies.put(UserType.NORMAL, new StrategyOperationNormal()); strategies.put(UserType.FULL, new StrategyOperationFull()); strategies.put(UserType.GOLD, new StrategyOperationGold()); } } En tu servicio haces uso del factory para obtener la estrategia y delegarle la lógica de cambio de tipo de UserType en el metodo “changeType” .\n@Service public class UserService { private final StrategyFactory strategyFactory; private final UserRepository repository; @Autowired public UserService(UserRepository repository, StrategyFactory strategyFactory) { this.repository = repository; this.strategyFactory = strategyFactory; } // other methods of service.. public User changeType(long id, UserType type) { Strategy strategy = strategyFactory.getStrategy(type); User user = repository.findOne(id); strategy.changeLimit(user); return repository.save(user); } } Probando tu Strategy #Usando el Controller de la app, que tenemos ya definido, creamos un User. Por defecto el User se crea con un tipo “NORMAL”.\nEl controller de nuestra app\n@RestController public class UserController { @Autowired private UserService userService; @RequestMapping(value = \u0026#34;/users\u0026#34;, method = RequestMethod.GET) public ResponseEntity\u0026lt;User\u0026gt; list() { List\u0026lt;User\u0026gt; users = userService.list(); return new ResponseEntity(users, HttpStatus.OK); } @RequestMapping(value = \u0026#34;/user\u0026#34;, method = RequestMethod.GET) public ResponseEntity\u0026lt;User\u0026gt; userById(@RequestParam(value = \u0026#34;id\u0026#34;) long id) { User user = userService.get(id); return new ResponseEntity(user, HttpStatus.OK); } @RequestMapping(value = \u0026#34;/create\u0026#34;, method = RequestMethod.POST) public ResponseEntity\u0026lt;User\u0026gt; create(@Valid @RequestBody User user) { User userCreated = userService.create(user); return new ResponseEntity(userCreated, HttpStatus.CREATED); } @RequestMapping(value = \u0026#34;/change_type\u0026#34;, method = RequestMethod.POST) public ResponseEntity\u0026lt;User\u0026gt; changeType(@RequestParam(value = \u0026#34;id\u0026#34;) long id, @RequestParam(value = \u0026#34;type\u0026#34;) UserType type) { User userCreated = userService.changeType(id, type); return new ResponseEntity(userCreated, HttpStatus.CREATED); } } El Service completo de nuestra app\n@Service public class UserService { private final StrategyFactory strategyFactory; private final UserRepository repository; @Autowired public UserService(UserRepository repository, StrategyFactory strategyFactory) { this.repository = repository; this.strategyFactory = strategyFactory; } public User get(long userId) { return repository.findOne(userId); } public List\u0026lt;User\u0026gt; list() { Iterable\u0026lt;User\u0026gt; users = repository.findAll(); List\u0026lt;User\u0026gt; list = new ArrayList\u0026lt;User\u0026gt;(); users.forEach(list::add); return list; } public User create(User user) { Strategy strategy = strategyFactory.getStrategy(UserType.NORMAL); strategy.changeLimit(user); return repository.save(user); } public User changeType(long id, UserType type) { Strategy strategy = strategyFactory.getStrategy(type); User user = repository.findOne(id); strategy.changeLimit(user); return repository.save(user); } } Ejecutas el rest api “/create” para crear un User que luego vamos a modificar. Enviamos en el body lo mínimo que necesita la entidad User.\nEl user se crea con el type “NORMAL” por defecto.\nLuego ejecutas el rest api “/change_type?id=1\u0026amp;type=FULL” para probar tu Servicio que usa el Factory y el Strategy. Aquí intentas cambiar el type de NORMAL a FULL para el user previamente creado.\nObserva que el user ha cambiado su límite acorde a la Strategy.\nDescarga este código completo desde GitHub # strategy-patter ","date":"23 oct 2017","permalink":"https://gustavopeiretti.com/strategy-pattern-spring-boot/","section":"Posts","summary":"\u003cp\u003eUn buen patrón para resolver la complejidad cuando debes implementar diferentes comportamientos según algún estado es el patrón strategy.\u003c/p\u003e","title":"Strategy Pattern con Spring Boot"},{"content":"En una aplicacion Spring en la cual exponemos endpoints Rest para que los clientes la consuman contamos con un manejador de excepciones de forma global para toda tu app.\nEsto nos da la flexibilidad de decidir que devolver al cliente para cada tipo de exception.\nEn este ejemplo te muestro como capturar una excepción cuando el cliente consume tu api y el body que te ha enviado no es válido.\nEn el caso de recibir un body inválido Spring crea una excepción MethodArgumentNotValidException y retorna un json que seguramente sobra para el cliente o información que te gustaría estandarizar para todos los errores de forma más acorde para tu api.\nEl modelo que representa el body que vas a recibir\npublic class User { @JsonProperty @NotBlank private String userName; @JsonProperty @NotBlank private String lastName; @JsonProperty @NotNull private Gender gender; @JsonProperty @Min(value = 18) @Max(value = 150) @NotNull private Integer age; @JsonProperty @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = \u0026#34;dd-MM-yyyy\u0026#34;) @Past @NotNull private Date dateOfBirth; Resultado de una exception MethodArgumentNotValidException\nEste es el resultado que recibes cuando Spring lanza una excepción al recibir un body inválido en un post. En este ejemplo se omite un tag requerido “dateOfBirth” en el body y por esta razón se lanza la excepción.\n¿Cómo debes capturar esta excepción y devolver algo a tu gusto?\nCreas la clase que representará la respuesta json #Defines tu clase con los json property que deseas mostrar como retorno del error. Suponemos que deseas devolver tres atributos simples, el mensaje, el status code, y la url.\nimport com.fasterxml.jackson.annotation.JsonProperty; public class ErrorInfo { @JsonProperty(\u0026#34;message\u0026#34;) private String message; @JsonProperty(\u0026#34;status_code\u0026#34;) private int statusCode; @JsonProperty(\u0026#34;uri\u0026#34;) private String uriRequested; public ErrorInfo(ApiException exception, String uriRequested) { this.message = exception.getMessage(); this.statusCode = exception.getStatusCode().value(); this.uriRequested = uriRequested; } public ErrorInfo(int statusCode, String message, String uriRequested) { this.message = message; this.statusCode = statusCode; this.uriRequested = uriRequested; } public String getMessage() { return message; } public int getStatusCode() { return statusCode; } public String getUriRequested() { return uriRequested; } } Creas el manejador global de excepciones ControllerAdvice #Para capturar este error debes crear una clase anotada @ControllerAdvice allí definirás cada tipo de error que deseas manejar @ExceptionHandler. Este método recibe el request y la excepción en particular. Puedes manejar todas las excepciones que desees.\nPara nuestro caso:\n@ControllerAdvice public class ErrorHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity\u0026lt;ErrorInfo\u0026gt; methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) { ErrorInfo errorInfo = new ErrorInfo(HttpStatus.BAD_REQUEST.value(), e.getMessage(), request.getRequestURI()); return new ResponseEntity\u0026lt;\u0026gt;(errorInfo, HttpStatus.BAD_REQUEST); } } Si pruebas el resultado verás esta respuesta, algo mejor, pero todavia el mensaje está poco claro.\nMejorar el mensaje #Para hacer más legible el mensaje puedes leer cada uno de los FieldError que son devueltos por MethodArgumentNotValidException.getBindingResult() para armar un string más legible.\n@ControllerAdvice public class ErrorHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity\u0026lt;ErrorInfo\u0026gt; methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) { // get spring errors BindingResult result = e.getBindingResult(); List\u0026lt;FieldError\u0026gt; fieldErrors = result.getFieldErrors(); // convert errors to standard string StringBuilder errorMessage = new StringBuilder(); fieldErrors.forEach(f -\u0026gt; errorMessage.append(f.getField() + \u0026#34; \u0026#34; + f.getDefaultMessage() + \u0026#34; \u0026#34;)); // return error info object with standard json ErrorInfo errorInfo = new ErrorInfo(HttpStatus.BAD_REQUEST.value(), errorMessage.toString(), request.getRequestURI()); return new ResponseEntity\u0026lt;\u0026gt;(errorInfo, HttpStatus.BAD_REQUEST); } } Observa el resultado nuevamente al enviar un post que no válida:\nConclusión #Puedes hacer uso de ControllerAdvice para capturar todas las excepciones de tu api y devolver un formato json estandarizado para toda tu aplicación.\nDescarga este código completo desde GitHub # spring-example-control-advice ","date":"22 sept 2017","permalink":"https://gustavopeiretti.com/spring-boot-capturar-las-excepciones-retornar-json-estandar/","section":"Posts","summary":"\u003cp\u003eEn una aplicacion Spring en la cual exponemos endpoints Rest para que los clientes la consuman contamos con un manejador de excepciones de forma global para toda tu app.\u003c/p\u003e","title":"Spring Boot – como capturar las excepciones y retornar un json estandar"},{"content":"Para este ejemplo desarrollarás una pequeña aplicación que recibirá un post con un body en json para crear un User mediante un rest api, también tendrás la opción de consultar los User guardados en la BD.\nPara definir un RestController en Spring Boot debes anotar tu controlador como un @RestController y anotar cada método que responderá con @RequestMapping.\nSpring hace uso de la anotación @RequestBody para mapear el json y la anotación @Valid para aplicar los constraints definidos en la clase para el caso de los post.\nEl endpoint /create recibirá un json con el User, lo validará y lo guardará en la BD. Crearemos otro endopoint /users para consultar todos los User en la BD También un /user?id=userId para mostrar un User por el id Este endpoint para crear, recibirá el json y lo mapeará contra el pojo User Configurar las dependencias #\u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-web\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework.boot\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-boot-starter-data-jpa\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.h2database\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;h2\u0026lt;/artifactId\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; Como configurar la Base de datos #El pom definiste una base de datos h2 que correrá embebida en la applicación, en nuestro caso persistirá solamente en memoria.\n¿Cómo definir una base de datos H2 en memoria en Spring?\nPara que la base de datos h2 persista solo en memoria debemos indicar el datasource en el application.properties de este modo:\n#in memory database spring.datasource.url = jdbc:h2:mem:example_db #in file database #spring.datasource.url = jdbc:h2:file:~example_db spring.datasource.username=sa spring.datasource.password= spring.datasource.driver-class-name=org.h2.Driver Configurar la app para Spring Boot # @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } Creas el modelo User #En el modelo que soporta nuestro json desde el post agrega los json property @JsonProperty indicando cómo deberá entenderse cada atributo del json. Además anotas las validaciones que deseas. Para este ejemplo, este mismo modelo lo usaremos para la persistencia por eso lo anotamos como @Entity.\nAlgunas de las validaciones que para este ejemplo son\n@NotNull : verifica que el valor no quede nulo. @NotBlank : verifica que el valor sea nulo o blanco para Strings. @Past : verifica que el valor esté en el pasado. @Min : valor mínimo posible. @Max : valor máximo posible. @Email : verifica que el string tenga un formato de email valido. @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @JsonProperty(\u0026#34;user_name\u0026#34;) @NotBlank private String userName; @JsonProperty(\u0026#34;last_name\u0026#34;) @NotBlank private String lastName; @JsonProperty(\u0026#34;gender\u0026#34;) @NotNull private Gender gender; @JsonProperty(\u0026#34;age\u0026#34;) @Min(value = 18) @Max(value = 150) @NotNull private Integer age; @JsonProperty(\u0026#34;birth\u0026#34;) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = \u0026#34;dd-MM-yyyy\u0026#34;) @Past @NotNull private Date dateOfBirth; // get and set... } package com.gp.model; public enum Gender { MALE, FEMALE; } Creas el servicio y el repository #Tu servicio recibirá las consultas desde el controller y la resolverá lógica del negocio, para el caso del acceso a la base este servicio consultará al repositorio especifico.\n@Service public class UserService { @Autowired private UserRepository repository; public User get(long userId) { return repository.findOne(userId); } public List\u0026lt;User\u0026gt; list() { Iterable\u0026lt;User\u0026gt; users = repository.findAll(); List\u0026lt;User\u0026gt; list = new ArrayList\u0026lt;User\u0026gt;(); users.forEach(list::add); return list; } public User create(User user) { return repository.save(user); } } El repositorio será un CrudRespository que nos da lo básico para este ejemplo.\nimport com.gp.model.User; import org.springframework.data.repository.CrudRepository; public interface UserRepository extends CrudRepository\u0026lt;User, Long\u0026gt; { } Definir un RestController con Spring Boot #Para crear un endpoint a fin de consultar Users y crearlos debes definir un controller de este modo usando las anotaciones @RestController y @RequestMapping\npackage com.gp.controllers; import com.gp.model.User; import com.gp.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.List; @RestController public class UserController { @Autowired private UserService userService; @RequestMapping(value = \u0026#34;/users\u0026#34;, method = RequestMethod.GET) public ResponseEntity\u0026lt;User\u0026gt; list() { List\u0026lt;User\u0026gt; users = userService.list(); return new ResponseEntity(users, HttpStatus.OK); } @RequestMapping(value = \u0026#34;/user\u0026#34;, method = RequestMethod.GET) public ResponseEntity\u0026lt;User\u0026gt; userById(@RequestParam(value = \u0026#34;id\u0026#34;) long id) { User user = userService.get(id); return new ResponseEntity(user, HttpStatus.OK); } @RequestMapping(value = \u0026#34;/create\u0026#34;, method = RequestMethod.POST) public ResponseEntity\u0026lt;User\u0026gt; create(@Valid @RequestBody User user) { User userCreated = userService.create(user); return new ResponseEntity(userCreated, HttpStatus.CREATED); } } Pruebas RestController con @Valid y @RequestBody #Prueba enviar tu json con un valor inválido:\nEnvía al rest /create vía post este body que contiene un valor invalido para el “age”.\nObserva la respuesta con un status 400 por no haber pasado los constraint del modelo.\nPrueba con valores válidos:\nAhora envía el json con todos lo valores correctos, el endpoint te devuelve el modelo que creado ya con un id asignado.\nConsulta de todos los User guardados:\nMediante el el endpoint /users podemos obtener toda la lista de User que hemos ido creando.\nDescarga este código completo # spring-boot-rest ","date":"7 ago 2017","permalink":"https://gustavopeiretti.com/spring-boot-rest-ejemplo-restcontroller-requestbody-valid/","section":"Posts","summary":"\u003cp\u003ePara este ejemplo desarrollarás una pequeña aplicación que recibirá un post con un body en json para crear un User mediante un rest api, también tendrás la opción de consultar los User guardados en la BD.\u003c/p\u003e","title":"Spring Boot Rest – Ejemplo RestController con RequestBody y Valid"},{"content":"Puedes utilizar lambda para crear métodos anónimos, pero hay casos en el que estas expresiones lambda no hacen otra cosa más que llamar a otro método.\nEn estos casos resulta más claro llamar al método directamente por su nombre.\nSi tienes una lista de personas de este modo y quieres ordenarla harías algo así de forma habitual con Java:\n// Without lambda expression Collections.sort(personList, new Comparator\u0026lt;Person\u0026gt;() { @Override public int compare(Person a, Person b) { return a.getBirthday().compareTo(b.getBirthday()); } }); Con lambda expressions puedes hacerlo aún mejor:\n// With lambda expression Collections.sort(personList, (Person a, Person b) -\u0026gt; { return a.getBirthday().compareTo(b.getBirthday()); } ); Observa la expresión lambda anterior. Lo que hace es en definitiva devolver un un int, si quisieras podrías llevarla a un método ‘compareByAge’ que haga lo mismo retornando el int con el resultado de la comparación, de este modo\npublic class Person { public enum Sex { MALE, FEMALE } private String name; private LocalDate birthday; private Sex gender; private String emailAddress; // static method for lambda method reference example public static int compareByAge(Person a, Person b) { return a.birthday.compareTo(b.birthday); } } Este método puedes usarlo así directamente aprovechando “Method References” de Java 8.\nLo que haces en definitiva es pasar el método a ser ejecutado como argumento\n// With method reference Collections.sort(personList, Person::compareByAge); Cómo usar la referencia a métodos en Java 8 #Existen varias formas de llamar a métodos por referencias:\nReferencia a métodos estáticos Referencia a métodos de instancia de un objeto Referencia a métodos de instancia de un objeto para un tipo en particular Referencias a un constructor // 1-With method reference Collections.sort(personList, Person::compareByAge); // -- // 2-Reference to a static method personList.forEach(System.out::println); // -- // 3-Reference to an instance method of a particular object class ComparisonProvider { public int compareByName(Person a, Person b) { return a.getName().compareTo(b.getName()); } public int compareByAge(Person a, Person b) { return a.getBirthday().compareTo(b.getBirthday()); } } ComparisonProvider myComparisonProvider = new ComparisonProvider(); personList.sort(myComparisonProvider::compareByAge); // -- // 4-Reference to an instance method of an arbitrary object of a particular type Collections.sort(personList, Person::compareByAge); // -- // 5-Reference to a constructor // Using a lambda expression Supplier\u0026lt;Person\u0026gt; personSupplier2 = () -\u0026gt; new Person(); Person personFromSupplier2 = personSupplier2.get(); // Using a method reference Supplier\u0026lt;Person\u0026gt; p = Person::new; Person onePerson = p.get(); ..\nReferencias:\n[https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html]2\n","date":"18 abr 2017","permalink":"https://gustavopeiretti.com/java-8-reference-method/","section":"Posts","summary":"\u003cp\u003ePuedes utilizar lambda para crear métodos anónimos, pero hay casos en el que estas expresiones \u003ca href=\"/java-8-usar-expresiones-lambda/\"\u003elambda\u003c/a\u003e no hacen otra cosa más que llamar a otro método.\u003c/p\u003e\n\u003cp\u003eEn estos casos resulta más claro llamar al método directamente por su nombre.\u003c/p\u003e","title":"Java 8 Reference method"},{"content":"Podemos definir Streams como una secuencia de funciones que se ejecutan una detrás de otra, de forma anidada.\nComparemos antes un Iterador con un Stream. Habitualmente cuando tenemos una collection lo que hacemos luego es iterar para realizar algo con dicha colección.\nUn Stream luce similar a una collection permitiendo además realizar operaciones directamente sobre el Stream. Cada operación devuelve un nuevo stream sobre el cual podemos seguir encadenando otras operaciones.\nString einstein = \u0026#34;La imaginación es más importante que el conocimiento\u0026#34;; String[] splited = einstein.split(\u0026#34;\\\\s+\u0026#34;); // Collection to Iterate List\u0026lt;String\u0026gt; words = Arrays.asList(splited); int count = 0; for(String w : words) { if(w.startsWith(\u0026#34;i\u0026#34;)) { count++; } } // JAVA 8 words.stream().filter(w -\u0026gt; w.startsWith(\u0026#34;i\u0026#34;)).count(); Las operaciones sobre Stream pueden ser intermedias o finales. En el caso de ser intermedias (filter, sorted, map) stream devolverá nuevamente otro stream permitiendo la continuidad de pasos o funciones sobre ella misma. Esto es llamado ‘pipelining’.\nIn computing, a pipeline is a set of data processing elements connected in series, where the output of one element is the input of the next one. The elements of a pipeline are often executed in parallel or in time-sliced fashion; in that case, some amount of buffer storage is often inserted between elements.\nWikipedia\nEstas son algunas funciones intermedias:\n// Intermediate operations Stream\u0026lt;Product\u0026gt; stream = products.stream(); Stream\u0026lt;Product\u0026gt; filterStream = stream.filter(p -\u0026gt; \u0026#34;B\u0026#34;.equals(p.getType())); Stream\u0026lt;Product\u0026gt; sorted = filterStream.sorted(comparing(Product::getPrice)); // Final operation sorted.forEach(System.out::println); Si no has leido sobre Lamndas te recomiendo una breve lectura antes.\nSupongamos que quieres procesar una lista de productos y realizar diferentes procesos como:\nrecorrer la lista filtrar durante el recorrido los elementos según alguna condición ordenar el resultado anterior mostrar el resultado Harías estas operaciones de forma tradicional así:\nList\u0026lt;Product\u0026gt; products = getProducts(); List\u0026lt;Product\u0026gt; resultFilter = new ArrayList\u0026lt;\u0026gt;(); // foreach filter for(Product p : products) { if(\u0026#34;B\u0026#34;.equals(p.getType())){ resultFilter.add(p); } } // sort Collections.sort(resultFilter, new Comparator\u0026lt;Product\u0026gt;() { @Override public int compare(Product p1, Product p2) { return p1.getPrice().compareTo(p2.getPrice()); } }); // print for(Product p: resultFilter) { System.out.println(p); } La clase Product que usas es:\npublic class Product { private long id; private String name; private String type; private Double price; // get and set... } Como usar Stream con Java 8 #Con Java 8 utilizando Streams y Lambdas haces las mismas operaciones anteriores de este modo:\nList\u0026lt;Product\u0026gt; products = getProducts(); // filter + sort + print products.stream().filter(p -\u0026gt;\u0026#34;B\u0026#34;.equals(p.getType())). sorted(comparing(Product::getPrice)). forEach(System.out::println); Puedes observar rápidamente la reducción en líneas de código y complejidad con este simple ejemplo.\nEjemplos de uso simple Stream con Java 8 #Observa esta operaciones usando Stream y como pueden ayudarte\nList\u0026lt;Product\u0026gt; products = getProducts(); // limit and foreach products.stream().limit(10).forEach(System.out::println); // filter and count long count = products.stream().filter(product -\u0026gt; product.getPrice() \u0026gt; 200d).count(); System.out.println(count); // collect ids List\u0026lt;Long\u0026gt; ids = products.stream().filter(product -\u0026gt; product.getPrice() \u0026gt; 200d). map(p -\u0026gt; p.getId()).collect(Collectors.toList()); ids.forEach(System.out::print); // print this ids.. //statistics DoubleSummaryStatistics doubleSummaryStatistics = products.stream().mapToDouble(p -\u0026gt; p.getPrice()).summaryStatistics(); System.out.println(doubleSummaryStatistics.getSum()); System.out.println(doubleSummaryStatistics.getMax()); System.out.println(doubleSummaryStatistics.getMin()); Referencias: [http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html]3\n…\nDescarga este código completo # java8_stream_example ","date":"13 abr 2017","permalink":"https://gustavopeiretti.com/java-8-uso-stream-basico/","section":"Posts","summary":"\u003cp\u003ePodemos definir Streams como una secuencia de funciones que se ejecutan una detrás de otra, de forma anidada.\u003c/p\u003e","title":"Java 8 Uso de Stream básico"},{"content":"Las expresiones lambda son una forma de crear funciones anónimas y que puedes utilzar en dónde el párametro recibido sea una interfaz funcional\nUna expresión lambda tiene esta forma\n(parameters) -\u0026gt; expression\n(parameters) -\u0026gt; { statements; }\nEstas son algunas expresiones lambda de ejemplo:\n() -\u0026gt; 5 // directamente devuelve un valor, return 5 x -\u0026gt; 2 * x // duplica el valor de x y lo retorna (x, y) -\u0026gt; x – y // toma dos valores y retorna su diferencia, aqui se infiere el tipo int (int x, int y) -\u0026gt; x + y // toma dos enteros y retorna su suma (String s) -\u0026gt; System.out.print(s) // toma un string y lo imprime en la consola Observa lo siguiente:\n-Si se tiene un solo parámetro no es obligatorio usar los paréntesis\nx -\u0026gt; 2 * x\n-Si no se tienen parámetros o si hay dos o más parámetros debemos usar paréntesis\n() -\u0026gt; 5\n(x, y) -\u0026gt; x – y\n-Si la expresión lambda es de una línea no se requieren llaves ni return.\n(String s) -\u0026gt; System.out.print(s)\nExpresiones lambda e Interfaces funcionales #Repasando lo dicho, las expresiones lambda son funciones anónimas que puedes utilizarlas en donde el parámetro sea una interfaz funcional.\nPor ejemplo, la interface Comparator es una interfaz funcional en el que usas su método abstracto ‘compare’ con expresiones lambda.\n@FunctionalInterface public interface Comparator\u0026lt;T\u0026gt; { int compare(T o1, T o2); } Puedes entonces crear un comparator utilizando una lambda expresión con esta interfaz funcional de este modo.\n// JAVA 8 with lambda Comparator\u0026lt;UserModel\u0026gt; userModelComparator = (UserModel u1, UserModel u2) -\u0026gt; u1.getPosition().compareTo(u2.getPosition()); // JAVA 7 lo harias de este modo Comparator\u0026lt;UserModel\u0026gt; userModelComparator = new Comparator\u0026lt;UserModel\u0026gt;() { @Override public int compare(UserModel u1, UserModel u2) { return u1.getPosition().compareTo(u2.getPosition()); } }; Algunos ejemplos de uso de lambdas #Prueba estos ejemplos simples en tu IDE para comprender mejor el uso de lambdas y cómo puedes simplicar significativamente tu código\npublic class LambdaExample { public static void main(String[] args) { List\u0026lt;UserModel\u0026gt; userModels = getUsers(); // JAVA 8 sort list using lambda userModels.sort((UserModel u1, UserModel u2)-\u0026gt; u1.getPosition().compareTo(u2.getPosition())); // JAVA 8 Foreach using lambda userModels.forEach((userModel)-\u0026gt;System.out.println(userModel)); // JAVA 8 Foreach using lambda and reference method userModels.forEach(System.out::println); // JAVA 8 Foreach using lambda with sentences userModels.forEach(user-\u0026gt;{ if(\u0026#34;Gustavo\u0026#34;.equals(user.getName())){ System.out.println(\u0026#34;Hi Gustavo!\u0026#34;); }else{ System.out.println(user.getName()); } }); // JAVA 8 Simple Runnable using lambda new Thread(() -\u0026gt; System.out.println(\u0026#34;Hi thread\u0026#34;)).start(); // JAVA 8 Runnable using lambda Runnable task = () -\u0026gt; { userModels.forEach(user-\u0026gt;{ System.out.println( \u0026#34;Hi \u0026#34; + user.getName() ); }); }; // start the thread new Thread(task).start(); } static class UserModel { String name; String position; public UserModel(String name, String position) { this.name = name; this.position = position; } public String getName() {return name;} public String getPosition() { return position; } } static List\u0026lt;UserModel\u0026gt; getUsers() { List\u0026lt;UserModel\u0026gt; userModels = new ArrayList\u0026lt;\u0026gt;(); userModels.add(new UserModel(\u0026#34;Gus\u0026#34;,\u0026#34;A\u0026#34;)); userModels.add(new UserModel(\u0026#34;Harrison\u0026#34;,\u0026#34;Z\u0026#34;)); userModels.add(new UserModel(\u0026#34;James\u0026#34;,\u0026#34;G\u0026#34;)); //.. more.. return userModels; } } …\n","date":"6 abr 2017","permalink":"https://gustavopeiretti.com/java-8-usar-expresiones-lambda/","section":"Posts","summary":"\u003cp\u003eLas expresiones lambda son una forma de crear funciones anónimas y que puedes utilzar en dónde el párametro recibido sea una \u003ca href=\"/java-8-interfaces-funcionales/\"\u003einterfaz funcional\u003c/a\u003e\u003c/p\u003e","title":"Java 8 Usar expresiones Lambda"},{"content":"El código de barra QR Code (Quick Response Code) es capaz de almacenar muchos más datos en menos tamaño en comparación con otros códigos de barra.\nVeamos con un breve ejemplo utilizando ZXing como crear códigos QR. Este ejemplo también te servirá para cualquier otro tipo de código soportado.\nImportar dependencia ZXing con maven # \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.zxing\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;core\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.3.0\u0026lt;/version\u0026gt; \u0026lt;type\u0026gt;pom\u0026lt;/type\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.google.zxing\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;javase\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.3.0\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; Como escribir código QR Code con ZXing #Debes utilizar la clase BitMatrix que recibirá el texto, formato y tamaño de la imagen. Luego te valdrás de MatrixToImageWriter para escribir este BitMatrix en un OutputStream.\nprivate static void writeQR(String text, String pathname) throws WriterException, IOException { int width = 600; int height = 400; String imageFormat = \u0026#34;png\u0026#34;; // \u0026#34;jpeg\u0026#34; \u0026#34;gif\u0026#34; \u0026#34;tiff\u0026#34; BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height); FileOutputStream outputStream = new FileOutputStream(new File(pathname)); MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, outputStream); } Como leer código QR Code con ZXing #Aquí debes utilizar BinaryBitmap y MultiFormatReader, esta última una clase que intentará decodificar el qr code del bitmap (nuestra imagen qr) y te devolverá el string resultante.\nprivate static String readQR(String pathname) throws FormatException, ChecksumException, NotFoundException, IOException { InputStream qrInputStream = new FileInputStream(pathname); BufferedImage qrBufferedImage = ImageIO.read(qrInputStream); LuminanceSource source = new BufferedImageLuminanceSource(qrBufferedImage); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Reader reader = new MultiFormatReader(); Result stringBarCode = reader.decode(bitmap); return stringBarCode.getText(); } Cómo leer y escribir código QR Code #El código completo te queda de esta manera\npublic class QRCodeExample { public static void main(String[] arg) { String pathname = \u0026#34;qrcode_example.png\u0026#34;; String textToQr = \u0026#34;La imaginación es más importante que el conocimiento\u0026#34;; try { writeQR(textToQr, pathname); String text = readQR(pathname); System.out.print(text); } catch (Exception e) { e.printStackTrace(); } } private static void writeQR(String text, String pathname) throws WriterException, IOException { int width = 600; int height = 400; String imageFormat = \u0026#34;png\u0026#34;; // \u0026#34;jpeg\u0026#34; \u0026#34;gif\u0026#34; \u0026#34;tiff\u0026#34; BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, width, height); FileOutputStream outputStream = new FileOutputStream(new File(pathname)); MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, outputStream); } private static String readQR(String pathname) throws FormatException, ChecksumException, NotFoundException, IOException { InputStream qrInputStream = new FileInputStream(pathname); BufferedImage qrBufferedImage = ImageIO.read(qrInputStream); LuminanceSource source = new BufferedImageLuminanceSource(qrBufferedImage); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Reader reader = new MultiFormatReader(); Result stringBarCode = reader.decode(bitmap); return stringBarCode.getText(); } } Otros códigos de barra soportados #Viendo el enum BarcodeFormat vemos estos códigos de barra soportados por ZXing\npublic enum BarcodeFormat { AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, RSS_14, RSS_EXPANDED, UPC_A, UPC_E, UPC_EAN_EXTENSION; } Referencias:\n[https://github.com/zxing/zxing]1 [https://zxing.github.io/zxing/project-info.html]2\nDescarga este código completo # qr_code_example_zxing.zip ","date":"16 feb 2017","permalink":"https://gustavopeiretti.com/java-codigos-barra-zxing/","section":"Posts","summary":"\u003cp\u003eEl código de barra QR Code (Quick Response Code) es capaz de almacenar muchos más datos en menos tamaño en comparación con otros códigos de barra.\u003c/p\u003e\n\u003cp\u003eVeamos con un breve ejemplo utilizando ZXing como crear códigos QR. Este ejemplo también te servirá para cualquier otro tipo de código soportado.\u003c/p\u003e","title":"Java Codigos de Barra con ZXing"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/tags/zxing/","section":"Tags","summary":"","title":"ZXing"},{"content":"Desde versiones anteriores conoces las interfaces SAM (Single Abstract Method interfaces).\nEs decir, interfaces que tienen un solo método abstracto; ejemplo de ellas encontramos a java.lang.Runnable\npublic interface Runnable { public abstract void run(); } Usualmente utilizamos este tipo de interfaz de forma anónima\npublic class ServiceExample { public void doWork() { new Thread(new Runnable() { @Override public void run() { System.out.println(\u0026#34;Running and working ...\u0026#34;); } }).start(); } } Java 8 mantiene estas SAM interfaces pero las llama Functional Interfaces. Creando además una anotación específica @FunctionalInterface que le dará la instrucción al compilador para que verifique que la interfaz anotada cumple con los requisitos de una interfaz funcional.\nRequisitos de una interfaz funcional. #Las interfaces funcionales tienen la característica de contar con un solo método abstracto.\nTambién pueden contar con más de un método siempre y cuando estos métodos sobrescriban métodos de la clase Object o sean métodos predeterminados, default.\nLos métodos predeterminados (marcados con “default”) no son abstractos, por lo cual una interfaz funcional puede definir varios métodos predeterminados.\nPor ejemplo, veamos esta interfaz ‘MyInterface’. Contiene un método funcional “doSomething”, dos métodos de la clase Object ‘toString’ y ‘equals’ y un método default ‘doSomething2’\n@FunctionalInterface public interface MyInterface { public void doSomething(); default public void doSomething2() { System.out.print(\u0026#34;Hi\u0026#34;);}; public String toString(); public boolean equals(Object o); } Si cometemos el error de intentar agregar dos métodos a nuestra interfaz funcional recibiremos este error “multiple non-overriding abstract methods found”\n@FunctionalInterface public interface MyInterface { public void doSomething(); // metodo funcional default public void doSomething2() { System.out.print(\u0026#34;Hi\u0026#34;);}; // metodo default public void doSomethingWrong(); // otro metodo funcional. mal! public String toString(); // sobreescribe public boolean equals(Object o); // sobreescribe } Bien y todo este rollo de interfaces funcionales ¿para que? Principalmente para trabajar con expresiones Lambda, que veremos en otro post.\n","date":"2 may 2016","permalink":"https://gustavopeiretti.com/java-8-interfaces-funcionales/","section":"Posts","summary":"\u003cp\u003eDesde versiones anteriores conoces las interfaces SAM (Single Abstract Method interfaces).\u003c/p\u003e\n\u003cp\u003eEs decir, interfaces que tienen un solo método abstracto; ejemplo de ellas encontramos a java.lang.Runnable\u003c/p\u003e","title":"Java 8 Interfaces Funcionales"},{"content":"Java 8 ha hecho cambios en las interfaces, las que ahora podemos agregarles métodos default (default methods). Esto permite agregar métodos a las interfaces sin necesidad de implementarlos en las clases hijas.\nEste método default provee un comportamiento por defecto para el caso en que la clase concreta no lo especifique.\nMétodo Default: #Sabemos que si definimos una interfaz y luego la modificamos agregando un nuevo método ‘romperemos’ todas las implementaciones y estaremos obligados a definir este nuevo método en las todas sus clases.\nPor ejemplo tenemos nuestra interfaz y nuestra clase de este modo:\ninterface InterfaceA { public void doSomething(); } public class MyImpl implements InterfaceA { @Override public void doSomething() { System.out.println(\u0026#34;Hello\u0026#34;); } } Luego agregamos a nuestra interfaz otro método “doMore()” sabemos que estaremos obligados a implemetar ese nuevo método en MyImpl;\ninterface InterfaceA { public void doSomething(); public void doMore(); } public class MyImpl implements InterfaceA { @Override public void doSomething() { System.out.println(\u0026#34;Hello\u0026#34;); } public void doMore() { System.out.println(\u0026#34;Hi\u0026#34;); } } Con Java 8 podemos definir un default method con implementación en la misma interfaz y que será utilizada por defecto si no se especifica en la clase concreta. Ya no estamos obligados a definirlo en MyImpl\ninterface InterfaceA { public void doSomething(); default public void doMore() { System.out.println(\u0026#34;Hi\u0026#34;); } } public class MyImpl implements InterfaceA { @Override public void doSomething() { System.out.println(\u0026#34;Hello\u0026#34;); } // esta clase ha \u0026#39;heredado\u0026#39; el metodo default doMore() } Dos interfaces con el mismo método default: #Podemos encontrarnos con dos Intefaces con el mismo método default, en este caso si una clase implementa ambas interfaces deberemos proveer la implementación de este método en la clase concreta para evitar esta exception “MyImpl inherits unrelated defaults”\nJava no tiene modo de saber qué método ejecutar, el de la InterfaceA o el de InterfaceB, por lo que debemos obligadamente implementarlo en la clase MyImpl.\ninterface InterfaceA { public void doSomething(); default public void doMore() { System.out.println(\u0026#34;Hi from A\u0026#34;); } } interface InterfaceB { default public void doMore() { System.out.println(\u0026#34;Hi from B\u0026#34;); } } public class MyImpl implements InterfaceA, InterfaceB { @Override public void doSomething() { System.out.println(\u0026#34;Hello\u0026#34;); } public void doMore() { System.out.println(\u0026#34;Hi from Class \u0026#34;); } } Invocar al método default desde la clase concreta: #Podríamos invocar desde la clase concreta MyImpl el método default de alguna de las interfaces de este modo.\npublic class MyImpl implements InterfaceA, InterfaceB { @Override public void doSomething() { System.out.println(\u0026#34;Hello\u0026#34;); } public void doMore() { InterfaceB.super.doMore(); } } Conclusión: #Podemos agregar default methods a la interfaz sin afectar las clases concretas que la implementan. Una implementación puede sobrescribir el método default. En el caso de ambigüedad, cuando hay dos interfaces con el mismo método la clase estará obligada a sobrescribir dicho método.\n","date":"21 abr 2016","permalink":"https://gustavopeiretti.com/java-8-default-methods-metodos-default/","section":"Posts","summary":"\u003cp\u003eJava 8 ha hecho cambios en las interfaces, las que ahora podemos agregarles métodos default (default methods). Esto permite agregar métodos a las interfaces sin necesidad de implementarlos en las clases hijas.\u003c/p\u003e","title":"Java 8 – Default Methods – Métodos Default"},{"content":"A partir de Java 7 contamos con la posibilidad de observar cambios en un directorio y de este modo supervisar determinados eventos tales como creación, modificación o eliminación ocurridos en alguna ruta de nuestro sistema operativo.\nLa clase específica para monitorear directorios a partir de Java 7 es WatchService.\n¿Cómo observar cambios en un directorio? #A fin de indicar que deseamos monitorear un directorio en particular debemos utilizar la clase Path y solicitarle un “WatchService”\nPath directoryToWatch = Paths.get(directory); WatchService watchService = directoryToWatch.getFileSystem().newWatchService(); Trabajando con el servicio WatchService y registrando eventos #Una vez que obtenemos el servicio, registramos el evento que deseamos monitorear. Por ejemplo creación, eliminación y modificación de archivos dentro del directorio.\ndirectoryToWatch.register(watchService, new WatchEvent.Kind[] {ENTRY_CREATE,ENTRY_DELETE,ENTRY_MODIFY}); Observando eventos #A partir de allí ya ‘tomamos’ el servicio obteniendo un token con los eventos que van sucediendo. El método “.take()” se quedará esperando que algo suceda en el directorio, para los eventos que hemos registrado.\nWatchKey key = watchService.take(); Veamos esto más claramente con un ejemplo:\npackage watcher; import java.io.IOException; import java.nio.file.*; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; public class FileChangeWatcher { public void doWath(String directory) throws IOException { System.out.println(\u0026#34;WatchService in \u0026#34; + directory); // Obtenemos el directorio Path directoryToWatch = Paths.get(directory); if (directoryToWatch == null) { throw new UnsupportedOperationException(\u0026#34;Directory not found\u0026#34;); } // Solicitamos el servicio WatchService WatchService watchService = directoryToWatch.getFileSystem().newWatchService(); // Registramos los eventos que queremos monitorear directoryToWatch.register(watchService, new WatchEvent.Kind[] {ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY}); System.out.println(\u0026#34;Started WatchService in \u0026#34; + directory); try { // Esperamos que algo suceda con el directorio WatchKey key = watchService.take(); // Algo ocurrio en el directorio para los eventos registrados while (key != null) { for (WatchEvent event : key.pollEvents()) { String eventKind = event.kind().toString(); String file = event.context().toString(); System.out.println(\u0026#34;Event : \u0026#34; + eventKind + \u0026#34; in File \u0026#34; + file); } // Volvemos a escuchar. Lo mantenemos en un loop para escuchar indefinidamente. key.reset(); key = watchService.take(); } } catch (InterruptedException e) { throw new RuntimeException(e); } } } A fin de ejecutar este ejemplo, podemos crear un “main”\nimport watcher.FileChangeWatcher; import java.io.IOException; public class App { public static void main(String[] args) throws IOException { FileChangeWatcher fileChangeWatcher = new FileChangeWatcher(); fileChangeWatcher.doWath(\u0026#34;C://developer//\u0026#34;); } } Si en la carpeta tuviera un archivo test.txt el cual abro y modifico, la salida sería la siguiente\nEvent : ENTRY_MODIFY in File test.txt De este modo contamos con la posibilidad de observar cambios en un directario para los eventos que deseemos de forma muy simple.\nUna alternativa a esto es utilizar Apache Commons IO que dispone de un File Monitor con el mismo proposito.\n","date":"18 sept 2015","permalink":"https://gustavopeiretti.com/observar-cambios-en-directorios-con-java/","section":"Posts","summary":"\u003cp\u003eA partir de Java 7 contamos con la posibilidad de observar cambios en un directorio y de este modo supervisar determinados eventos tales como creación, modificación o eliminación ocurridos en alguna ruta de nuestro sistema operativo.\u003c/p\u003e","title":"Observar cambios en directorios con Java"},{"content":"Esta es una introducción, bastante simple, a fin de comprender acerca de patrones. Los patrones son expresiones que podemos utilizar para buscar dentro de un texto.\nDicho de otra forma cuando creamos una “expresión regular” estamos definiendo un patrón de búsqueda para localizar cadenas de caracteres.\nEn java contamos con dos clases importantes para esto:\nPattern es una representación de la expresión regular que ha sido ‘compilada’ para ser utilizada. Es decir, es una expresión que define un patrón de búsqueda para nuestra cadena de caracteres.\nMatcher es un objeto que surge a partir del patrón (Pattern) previamente creado al cual le pasamos la cadena en dónde deseamos realizar la búsqueda de nuestra expresión.\nNecesitamos dos pasos para empezar, primero compilar nuestro patrón utilizando una expresión de búsqueda o regex.\nPattern.compile(“nuestra_expresion_de_busqueda_o_regex”)\nLuego crear un matcher a partir del pattern indicando sobre qué cadena de caracteres deseamos realizar la búsqueda.\nMatcher m = p.matcher(“abaaaba”);\nVeamos este código\npublic class RegexSmall { public static void main(String[] args) { Pattern p = Pattern.compile(\u0026#34;ab\u0026#34;); // pattern Matcher m = p.matcher(\u0026#34;abaaaba\u0026#34;); // source while (m.find()) { System.out.print(m.start() + \u0026#34; \u0026#34;); } } }\u0026lt;/code\u0026gt;\u0026lt;/pre\u0026gt; En nuestro texto en dónde buscaremos (source) los índices (como mucho en Java) empiezan en cero. source: “abaaaba” index: 0123456 pattern: ab salida: 0 4 En nuestro ejemplo anterior se encontrará el patrón en la posición 0 y en la posición 4 por lo que la salida será 0 4 En general la expresión de búsqueda busca de izquierda a derecha y una vez que ha encontrado un carácter este no es reutilizado. Se dice que el carácter fue **consumido**. Por ejemplo si variamos nuestra expresión de esta forma ```java ... Pattern p = Pattern.compile(\u0026#34;aba”); // pattern Matcher m = p.matcher(\u0026#34;abababa\u0026#34;); // source ...\u0026lt;/code\u0026gt;\u0026lt;/pre\u0026gt; El resultado seguirá siendo 0 4 porque si bien en la expresión podríamos suponer que existe en el indice 2 la expresión de busqueda, el valor ya ha sido utilizado. abababa -\u0026gt; indice 0 (fueron consumidos los tres primeros caracteres) abababa -\u0026gt; el indice 2 ya fue utilizado anteriormente, no se puede utilizar abababa -\u0026gt; indice 4 **Grupos** Podemos utilizar también grupos de caracteres y rangos de caracteres de esta forma [abc] Buscará solo los caracteres a, b, c [a-f] Buscará solo a, b, c, d, e, o f [a-fA-F] Buscará tambien el rango entre a y f (a, b, c, d, e, o f) y tambien las mayúsculas Note que el primero es un grupo que define sólo tres caracteres y el segundo es un rango que inicia en a y termina en f. El tercer caso es similar al segundo, incluyendo las mayúsculas Por ejemplo si tenemos source: \u0026amp;#8220;cafeBABE\u0026amp;#8221; index: 01234567 pattern: [a-cA-C] la salida será: 0 1 4 5 6. **Utilizando Metacaracteres** Veremos sólo algunos para entender, son los que en definitiva se necesitan a menudo y en la certificación para Java \\d Un digito \\s Un espacio en blanco \\w Un caracter (letras, digitos, o \u0026amp;#8220;_\u0026amp;#8221; (guion bajo)) . punto (dot) Por ejemplo si tenemos source: “a12c3e456f” index: 0123456789 pattern: \\d la salida será: 1 2 4 6 7 8 (se han buscado solo los dígitos) Por ejemplo si tenemos source: \u0026amp;#8220;a 1 56 _Z\u0026amp;#8221; index: 012345678 pattern: \\w la salida será: 0 2 4 5 7 8 (se han buscado letras, digitos y guiones bajos) Además del los valores \\d dígitos) \\s (espacios en blanco) y \\w (letras,dígitos, o \u0026amp;#8220;_\u0026amp;#8221; guión bajo) tenemos el punto (dot) el cual indica ‘cualquier carácter en dicha posición’. Por ejemplo para source: \u0026amp;#8220;ac abc a c\u0026amp;#8221; pattern: a.c (observemos el punto entre \u0026amp;#8216;a\u0026amp;#8217; y \u0026amp;#8216;c\u0026amp;#8217;) la salida será: 3 7 en la posicion 3 tenemos abc (la letra b fue encontrada por el punto en nuestro pattern) en la posición 7 tenemos a c (el espacio fue encontrado por el punto en nuestro pattern) **Cuantificadores (quantifiers)** Hay un grupo de regex llamados cuantificadores (quantifiers) que nos permiten definir este concepto de “cero / uno o más”. Tenemos estos cuantificadores * Uno o más * Cero o más ocurrencias ? Cero o una ocurrencia Por ejemplo para “uno o más” el cuantificador es el simbolo ‘más’ “+” que podemos utilizar de esta forma. source: \u0026amp;#8220;1 a12 234b\u0026amp;#8221; pattern: \\d+ Buscar uno o mas digitos la salida sera: 0 3 6 Tenemos en 0 el valor 1 3 el valor 12 6 el valor 234 Veamos este otro ejemplo para entender otro concepto llamado c**uantificador greedy y cuantificador reluctant.** Por ejemplo si tenemos source: yyxxxyxx pattern: .*xx la salida será: 0 (cero) La salida nos indica que el resultado está en el indice 0 cero. Esto es correcto porque si observamos yyxxxyxx toda la cadena termina en ‘xx’ y lo que estamos pidiendo es ‘busque cualquier carácter (lo hemos dicho con el punto y el asterisco) que termine el xx’. Esto es lo que hace el cuantificador greedy, mira primero toda la cadena completa y luego busca de derecha a izquierda. Ahora, si quisiéramos como resultado estos dos valores en yyxxxyxx que terminan en xx El valor yyxx ubicado a partir del indice 0 El valor xyxx ubicado a partir del indice 4 Para este caso es cuando utilizamos el reluctant (agregando un ? al cuantificador). El cuantificador reluctant lo que hace es empezar leyendo el texto de izquierda a derecha hasta hallar la coincidencia buscada. Si cambiamos el pattern de esta forma source: yyxxxyxx pattern: .*?xx usando el reluctant *?, obtenemos lo siguiente: 0 yyxx 4 xyxx Resumiendo lo anterior uno o mas: + greedy, +? reluctant cero o mas: _greedy, _? reluctant cero o uno: ? greedy, ?? reluctant () \u0026lt;div style=\u0026#34;font-size: 0px; height: 0px; line-height: 0px; margin: 0; padding: 0; clear: both;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; ","date":"3 sept 2014","permalink":"https://gustavopeiretti.com/introduccion-usando-pattern-y-matcher/","section":"Posts","summary":"\u003cp\u003eEsta es una introducción, bastante simple, a fin de comprender acerca de patrones. Los patrones son expresiones que podemos utilizar para buscar dentro de un texto.\u003c/p\u003e","title":"Introducción usando Pattern y Matcher"},{"content":"","date":null,"permalink":"https://gustavopeiretti.com/es/page/","section":"Pages","summary":"","title":"Pages"}]