¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
¿Buscas nuestro logo?
Aquí te dejamos una copia, pero si necesitas más opciones o quieres conocer más, visita nuestra área de marca.
dev
Daniel Peña 02/04/2025 Cargando comentarios…
En el post anterior vimos cómo empaquetar y distribuir nuestras recetas que contenían pasos y ejecuciones de recetas públicas.
En muchos casos, esas recetas pueden resolver nuestros problemas, pero hay veces que necesitamos hacer cosas más ad-hoc, por ejemplo, renombrar variables, cambiar signaturas de métodos y refactors que nos acompañan en el día a día.
En esta segunda parte del post vamos a ver cómo realizar modificaciones de clases Java internamente.
Vamos a definir una nueva variable en una clase. Debemos usar el "Visitor" de ClassDeclaration, ya que es a nivel de clase donde vamos a meter la variable. Nuestra receta quedará así:
package com.openrewrite.demo.recipe;
import static java.util.Collections.emptyList;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;
public class AddClassVariable extends Recipe {
private String variableAnnotations = "@Deprecated";
private String variableModifiers = "public final";
private String variableRawStatement = "Random variableA";
private String variableInitialization = " new Random()";
@Override
public String getDescription() {
return "Add Class Variable";
}
@Override
public String getDisplayName() {
return "Add Class Variable";
}
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new AddClassRandomVariableDeclaration();
}
public class AddClassRandomVariableDeclaration extends JavaIsoVisitor<ExecutionContext> {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext p) {
J.ClassDeclaration c = classDecl;
if(!classVarAlreadyExists(c, variableRawStatement)) { //Idempotent
JavaTemplate varDeclarationTemplate = JavaTemplate
.builder("#{} \n #{} #{} = #{};")
.contextSensitive()
.build();
Statement addVariableStatement = maybeAutoFormat(c, c.withBody(
varDeclarationTemplate.apply(
new Cursor(getCursor(), c.getBody().withStatements(emptyList())),
c.getBody().getCoordinates().lastStatement(),
variableAnnotations,
variableModifiers ,
variableRawStatement,
variableInitialization
)), p).getBody().getStatements().get(0);
c = c.withBody(c.getBody().withStatements(ListUtils.concat(c.getBody().getStatements(), addVariableStatement)));
maybeAddImport("java.util.Random",null, false); //OnlyIfReferenced=false, because at this point is not evaluated that the new var exists, so is not referenced already
}
return c;
}
/**
* Returns true if exist a class Var Declaration that name match
* @param classDecl
* @return
*/
private boolean classVarAlreadyExists(J.ClassDeclaration classDecl, String typeAndNameVar) {
return classDecl.getBody().getStatements().stream()
.filter(statement -> statement instanceof J.VariableDeclarations)
.map(J.VariableDeclarations.class::cast)
.anyMatch(varDeclaration -> varDeclaration.toString().contains(typeAndNameVar));
}
}
}
Vemos que para cosas complejas podemos hacer uso de JavaTemplate. Esta utilidad nos permite escribir bloques Java de manera más sencilla como si fueran templates. En este ejemplo, además, vamos a crear una variable de tipo random, con lo que vamos a necesitar añadir ese import. Compilamos nuestro recetario:
mvn clean install
Y ejecutamos en el proyecto:
cd /tmp/testing-recipe-project
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=com.openrewrite.demo.recipe:dppware-recipe:1.0-SNAPSHOT \
-Drewrite.activeRecipes=com.openrewrite.demo.recipe.AddClassVariable
[INFO] Using active recipe(s) [com.openrewrite.demo.recipe.AddClassVariable]
[INFO] Using active styles(s) []
[INFO] Validating active recipes...
[INFO] Project [testing-recipe-project] Resolving Poms...
[INFO] Project [testing-recipe-project] Parsing source files
[INFO] Running recipe(s)...
[WARNING] Changes have been made to src/main/java/com/dppware/testing/Ship.java by:
[WARNING] com.openrewrite.demo.recipe.AddClassVariable
[WARNING] Changes have been made to src/main/java/com/dppware/testing/App.java by:
[WARNING] com.openrewrite.demo.recipe.AddClassVariable
[WARNING] Changes have been made to src/test/java/com/dppware/testing/AppTest.java by:
[WARNING] com.openrewrite.demo.recipe.AddClassVariable
[WARNING] Please review and commit the results.
Como vemos, nos ha añadido la declaración de la variable a todas las clases del proyecto. En muchos casos queremos establecer una condición para la ejecución de nuestro "Visitor".
Las precondiciones son clases Java que filtran antes de la ejecución del "Visitor". Vamos a deshacer los cambios ejecutados anteriormente y vamos crear la variable solo si la clase se extiende de una determinada clase padre. Descartamos los cambios anteriores para poder ejecutar nuevamente:
git stash
Creamos una clase "Vehicle" solo con el propósito de que "Ship" extienda de ella. Nos quedará así:
package com.openrewrite.demo.testing;
public class Vehicle {
}
Y modificamos nuestra clase "Ship" para que extienda de "Vehicle":
/*Quien tuviere narices de copiar este código será castigado con 3 flexiones y 2 cafés de la máquina del pasillo*/
package com.openrewrite.demo.testing;
/*This is AddCommentToClassDeclaration*/
public class Ship extends Vehicle{
//comment
private String propertyA;
}
Creamos la precondition de manera genérica, es decir, en el constructor podemos indicar qué clase es la que esperamos que extienda para cumplirse la condición.
package com.openrewrite.demo.recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.marker.SearchResult;
import lombok.EqualsAndHashCode;
import lombok.Value;
@Value
@EqualsAndHashCode(callSuper = false)
public class PreconditionClassExtends<P> extends JavaIsoVisitor<P> {
/**
* Target extends className
*/
String extendsClass ;
public PreconditionClassExtends(String extendsClass) {
this.extendsClass = extendsClass;
}
/**
* Solo declaramos el visitor donde esperamos encontrar la condición
*/
@Override
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, P p) {
if(classDecl.getExtends()!=null && classDecl.getExtends().getType().toString().equals(extendsClass)) {
return SearchResult.found(classDecl);
}
return super.visitClassDeclaration(classDecl, p);
}
}
Modificamos nuestra receta cambiando el método getVisitor para que, si se da la condición de que se extiende de "Vehicle", devuelva la ejecución del "Visitor".
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
Preconditions.or(
new PreconditionClassExtends<>("com.openrewrite.demo.testing.Vehicle")),
new AddClassRandomVariableDeclaration());
}
Vamos a compilar nuestro recetario:
mvn clean install
Y lo ejecutamos sobre el proyecto:
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=com.openrewrite.demo.recipe:dppware-recipe:1.0-SNAPSHOT \
-Drewrite.activeRecipes=com.openrewrite.demo.recipe.AddClassVariable
Por último, comprobamos que solo se ha visto afectada la clase "Ship".
Vamos a crear un método usando una precondición si el método no existe en la clase. Es decir, si la clase ya lo tiene entonces no lo mete.
Preparamos el código del proyecto añadiendo un método llamado mayúsculas a la clase Vehicle.java
public class Vehicle {
protected String mayusculas(String key){
return key.toUpperCase();
}
}
Preparamos una precondition que se pueda reutilizar:
package com.openrewrite.demo.recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J.ClassDeclaration;
import org.openrewrite.java.tree.J.MethodDeclaration;
import org.openrewrite.marker.SearchResult;
public class PreconditionHasMethodWithName<P> extends JavaIsoVisitor<P> {
/**
* Target extends className
*/
String methodName ;
public PreconditionHasMethodWithName(String methodName) {
this.methodName = methodName;
}
/**
* Solo declaramos el visitor donde esperamos encontrar la condición
*/
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, P p) {
if(method.getSimpleName().equals(methodName)) {
return SearchResult.found(method);
}
return super.visitMethodDeclaration(method, p);
};
}
Preguntaremos si la clase declara un método llamado mayúsculas y, si es así, metemos otro método que hará uso de él. La receta nos queda así:
package com.openrewrite.demo.recipe;
import static java.util.Collections.emptyList;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;
public class AddClassMethod extends Recipe {
private String methodName = "concatenateWithMe";
private final String methodTemplate = "public String #{}(#{} , #{}) {return this.mayusculas(#{} + #{});}";
@Override
public String getDescription() {
return "Add Class Method";
}
@Override
public String getDisplayName() {
return "Add Class Method";
}
/**
* Main execution with Matchers Preconditions
*/
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
Preconditions.or(
new PreconditionHasMethodWithName<>("mayusculas")),
new AddClassMethodVisitor());
}
public class AddClassMethodVisitor extends JavaIsoVisitor<ExecutionContext> {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext p) {
J.ClassDeclaration c = classDecl;
if(!classMethodAlreadyExists(c, methodName)) { //Idempotent
JavaTemplate varDeclarationTemplate = JavaTemplate
.builder(methodTemplate)
.contextSensitive()
.build();
Statement addVariableStatement = maybeAutoFormat(c, c.withBody(
varDeclarationTemplate.apply(
new Cursor(getCursor(), c.getBody().withStatements(emptyList())),
c.getBody().getCoordinates().lastStatement(),
methodName,
"String arg1" ,
"String arg2",
"arg1",
"arg2"
)), p).getBody().getStatements().get(0);
c = c.withBody(c.getBody().withStatements(ListUtils.concat(c.getBody().getStatements(), addVariableStatement)));
}
return c;
}
/**
* Returns true if exist a class Var method that name match
* @param classDecl
* @return
*/
private boolean classMethodAlreadyExists(J.ClassDeclaration classDecl, String typeAndNameMethod) {
return classDecl.getBody().getStatements().stream()
.filter(statement -> statement instanceof J.MethodDeclaration)
.map(J.MethodDeclaration.class::cast)
.anyMatch(varDeclaration -> varDeclaration.toString().contains(typeAndNameMethod));
}
}
}
Como podemos ver, hemos vuelto a hacer uso de las preconditions y también del JavaTemplate para la declaración del método. Compilamos y preparamos la ejecución:
cd /tmp/testing-recipe-project
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=com.openrewrite.demo.recipe:dppware-recipe:1.0-SNAPSHOT \
-Drewrite.activeRecipes=com.openrewrite.demo.recipe.AddClassMethod
[WARNING] Changes have been made to src/main/java/com/dppware/testing/Vehicle.java by:
[WARNING] com.openrewrite.demo.recipe.AddClassMethod
[WARNING] Please review and commit the results.
Vemos que nos ha añadido el método “concatenateWithMe” en la clase "Vehicle", que es la que declara el método.
public class Vehicle {
protected String mayusculas(String key){
return key.toUpperCase();
}
public String concatenateWithMe(String arg1, String arg2) {
return this.mayusculas(arg1 + arg2);
} }
Vamos a buscar un método que, si existe, cambie la primera línea para que sea una ejecución personalizada. En este caso, un new de un objeto “Ship”. Por simplificar, vamos a usar la precondition PreconditionHasMethodWithName.
Si la clase tiene un método con nombre main, vamos a modificar el contenido añadiendo una sentencia a la ejecución que instancie un “Ship”.
Nuestra receta queda así:
AddStatementToMethod
package com.openrewrite.demo.recipe;
import static java.util.Collections.emptyList;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;
import org.openrewrite.java.tree.J.MethodDeclaration;
public class AddStatementToMethod extends Recipe {
private final String statementTemplate = "Ship ship = new Ship()";
@Override
public String getDescription() {
return "AddStatementToMethod";
}
@Override
public String getDisplayName() {
return "AddStatementToMethod";
}
/**
* Main execution with Matchers Preconditions
*/
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
Preconditions.or(
new PreconditionHasMethodWithName<>("main")),
new AddStatementToMethodVisitor());
}
public class AddStatementToMethodVisitor extends JavaIsoVisitor<ExecutionContext> {
@Override
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, ExecutionContext p) {
J.MethodDeclaration m = super.visitMethodDeclaration(method, p);
if(!invocationStatementExist(m, statementTemplate)) { //Idempotent
JavaTemplate invocationStatementTemplate = JavaTemplate
.builder(statementTemplate)
.contextSensitive()
.build();
Statement addMethodInvocationStatement = maybeAutoFormat(m, m.withBody(
invocationStatementTemplate.apply(
new Cursor(getCursor(), m.getBody().withStatements(emptyList())),
m.getBody().getCoordinates().lastStatement()
)), p).getBody().getStatements().get(0);
m = m.withBody(m.getBody().withStatements(ListUtils.concat(m.getBody().getStatements(), addMethodInvocationStatement)));
maybeAddImport("com.openrewrite.demo.testing.Ship",null, false); //OnlyIfReferenced=false, because at this point is not evaluated that the new var exists, so is not referenced already
}
return m;
}
/**
* Returns true if exist the invocation
* @param classDecl
* @return
*/
private boolean invocationStatementExist(MethodDeclaration method, String invocation) {
return method.getBody().getStatements().stream()
.anyMatch(stm -> stm.toString().contains(invocation));
}
}
}
Preparamos la ejecución y nos queda así:
cd /tmp/testing-recipe-project
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=com.openrewrite.demo.recipe:dppware-recipe:1.0-SNAPSHOT \
-Drewrite.activeRecipes=com.openrewrite.demo.recipe.AddStatementToMethod
[INFO] Project [testing-recipe-project] Resolving Poms...
[INFO] Project [testing-recipe-project] Parsing source files
[INFO] Running recipe(s)...
[WARNING] Changes have been made to src/main/java/com/dppware/testing/App.java by:
[WARNING] com.openrewrite.demo.recipe.AddStatementToMethod
[WARNING] Please review and commit the results.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
En el diff vemos que ha encontrado el método main y ha incluido el new “Ship”.
@@ -10,5 +10,6 @@ public class App
public static void main( String[] args )
{
System.out.println( "Hello World!" );
+ Ship ship = new Ship();
}
}
Esta receta va a crear un constructor con 2 parámetros. Esos 2 parámetros tendremos que definirlos a nivel de clase para poder asignarlos al constructor, así que esta receta va a ser un poco más compleja.
Vamos a cambiar el constructor de “Ship” para que pida 2 argumentos. Si cambiamos eso, el new que estamos haciendo en la clase App.java#main va a fallar porque necesitará proporcionar esos argumentos.
Esta receta requiere de 2 ejecuciones (recetas). La primera receta AddConstructorParametrizedToClass añadirá los campos y creará el constructor. La segunda receta UpdateConstructorInvocation, buscará las invocaciones al constructor de “Ship” y las cambiará para añadirle los nuevos argumentos que le vamos a pasar como argumentos en la receta. Nos quedarán así:
package com.openrewrite.demo.recipe;
import static java.util.Collections.emptyList;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;
public class AddConstructorParametrizedToClass extends Recipe {
private String arg1 = "private String argumentA";
private String argB = "private String argumentB";
private final String constructorTemplate = "public Ship (#{} , #{}) {this.#{} = #{}; \n this.#{} = #{};}";
@Override
public String getDescription() {
return "AddConstructorParametrizedToClass";
}
@Override
public String getDisplayName() {
return "AddConstructorParametrizedToClass";
}
/**
* Main execution with Matchers Preconditions
*/
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new AddClassParametrizedConstructorVisitor();
}
public class AddClassParametrizedConstructorVisitor extends JavaIsoVisitor<ExecutionContext> {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext p) {
J.ClassDeclaration c = classDecl;
if(classDecl.getName().getSimpleName().equals("Ship")) {
c = createPropertyA("private String argumentA", c, p);
c = createPropertyA("private String argumentB", c, p);
c = createConstructor(c,p);
}
return c;
}
private J.ClassDeclaration createPropertyA(String template, J.ClassDeclaration c, ExecutionContext p){
if(!classVarAlreadyExists(c, template)) {
JavaTemplate varATemplate = JavaTemplate.builder(template).contextSensitive().build();
Statement addVarAStatement = maybeAutoFormat(c,
c.withBody( varATemplate.apply(new Cursor(getCursor(), c.getBody().withStatements(emptyList())),c.getBody().getCoordinates().lastStatement())), p).getBody().getStatements().get(0);
c = c.withBody(c.getBody().withStatements(ListUtils.concat(c.getBody().getStatements(), addVarAStatement)));
}
return c;
}
private J.ClassDeclaration createConstructor(J.ClassDeclaration c, ExecutionContext p){
if(!classMethodAlreadyExists(c, "nolose")) {
JavaTemplate constructorDeclarationTemplate = JavaTemplate.builder(constructorTemplate).contextSensitive().build();
Statement addParametrizedConstructorStatement = maybeAutoFormat(c, c.withBody(
constructorDeclarationTemplate.apply(
new Cursor(getCursor(), c.getBody().withStatements(emptyList())),
c.getBody().getCoordinates().lastStatement(),
"String argumentA" ,
"String argumentB",
"argumentA","argumentA",
"argumentB","argumentB"
)), p).getBody().getStatements().get(0);
c = c.withBody(c.getBody().withStatements(ListUtils.concat(c.getBody().getStatements(), addParametrizedConstructorStatement)));
}
return c;
}
/**
* Returns true if exist a class Var Declaration that name match
* @param classDecl
* @return
*/
private boolean classVarAlreadyExists(J.ClassDeclaration classDecl, String typeAndNameMethod) {
return classDecl.getBody().getStatements().stream()
.filter(statement -> statement instanceof J.VariableDeclarations)
.map(J.VariableDeclarations.class::cast)
.anyMatch(varDeclaration -> varDeclaration.toString().contains(typeAndNameMethod));
}
/**
* Returns true if exist a class Var method that name match
* @param classDecl
* @return
*/
private boolean classMethodAlreadyExists(J.ClassDeclaration classDecl, String typeAndNameMethod) {
return classDecl.getBody().getStatements().stream()
.filter(statement -> statement instanceof J.MethodDeclaration)
.map(J.MethodDeclaration.class::cast)
.anyMatch(method -> method.isConstructor() && method.getParameters().size()==2);
}
}
}
Y la otra:
package com.openrewrite.demo.recipe;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.J.NewClass;
import org.openrewrite.java.tree.TypeUtils;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.Value;
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
public class UpdateConstructorInvocation extends Recipe {
@Option(displayName = "Target Constructor name",
description = "Target Constructor name.",
example = "com.dppware.Ship")
String constructorName ;
@Option(displayName = "Target Constructor first argument",
description = "Target Constructor first argument",
example = "hola")
String firstArgValue ;
@Option(displayName = "Target Constructor second argument",
description = "Target Constructor second argument",
example = "adios")
String secondArgValue ;
@Override
public String getDescription() {
return "Update invocations to constructor";
}
@Override
public String getDisplayName() {
return "Unpdate invocations to constructor";
}
/**
* Main execution with Matchers Preconditions
*/
@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new AddClassParametrizedConstructorVisitor();
}
public class AddClassParametrizedConstructorVisitor extends JavaIsoVisitor<ExecutionContext> {
@Override
public NewClass visitNewClass(NewClass newClass, ExecutionContext p) {
NewClass newInvocation = super.visitNewClass(newClass, p);
if(TypeUtils.isOfClassType(newInvocation.getType(), constructorName)) {
return JavaTemplate.builder("new Ship(\""+firstArgValue+"\" , \""+secondArgValue+"\" ); " )
.build()
.apply(updateCursor(newInvocation), newInvocation.getCoordinates().replace());
}
return newClass;
}
}
}
Compilamos el recetario:
mvn clean install
Queremos que estas 2 recetas se ejecuten en una transacción completa, ya que si lanzamos la primera, no vamos a poder lanzar la segunda porque dejaremos el código en un estado inestable que no llega a compilar.
A partir de un fichero YAML, creamos la configuración para ejecutar las 2 recetas, como hemos hecho en otras ocasiones.
Nos quedará así:
recipe_change_constructor.yaml
type: specs.openrewrite.org/v1beta/recipe
name: com.openrewrite.demo.ChangeConstructorExample
displayName: Change Ship constructor and invocations
recipeList:
- com.openrewrite.demo.recipe.AddConstructorParametrizedToClass
- com.openrewrite.demo.recipe.UpdateConstructorInvocation:
constructorName: com.openrewrite.demo.testing.Ship
firstArgValue: hola
secondArgValue: adios
Y la ejecución indicando el fichero de configuración será así:
cd /tmp/testing-recipe-project
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=com.openrewrite.demo.recipe:dppware-recipe:1.0-SNAPSHOT \
-Drewrite.activeRecipes=com.openrewrite.demo.ChangeConstructorExample \
-Drewrite.configLocation=/home/dpena/development/workspaces/dppware/gitlab/dppware-adhoc/back/pocs/openrewrite/recipes/recipe_change_constructor.yaml
Analizamos el diff y vemos que ha cambiado todo:
public static void main( String[] args )
{
System.out.println( "Hello World!" );
- Ship ship = new Ship();
+ Ship ship = new Ship("hola", "adios" );
}
}
diff --git a/src/main/java/com/dppware/testing/Ship.java b/src/main/java/com/dppware/testing/Ship.java
index 702591d..ff4e5b0 100644
--- a/src/main/java/com/dppware/testing/Ship.java
+++ b/src/main/java/com/dppware/testing/Ship.java
@@ -11,4 +11,10 @@ public class Ship extends Vehicle{
private String propertyA;
@Deprecated
public final Random variableA = new Random();
+ private String argumentA;
+ private String argumentB;
+ public Ship(String argumentA, String argumentB) {
+ this.argumentA = argumentA;
+ this.argumentB = argumentB;
+ }
Hemos visto cómo podemos escribir recetas propias si las públicas que existen no nos valen o necesitamos hacer algo más específico. Espero que esta guía te haya resultado útil y, si tienes dudas, te leo en comentarios👇
Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.
Cuéntanos qué te parece.