diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java b/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
index 07eb6142de..62c038b360 100644
--- a/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
+++ b/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
@@ -35,7 +35,10 @@ static boolean isGetter(Cursor cursor) {
if (!(cursor.getValue() instanceof J.MethodDeclaration)) {
return false;
}
- J.MethodDeclaration method = cursor.getValue();
+ return isGetter((J.MethodDeclaration) cursor.getValue());
+ }
+
+ static boolean isGetter(J.MethodDeclaration method) {
if (method.getMethodType() == null) {
return false;
}
diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/UseLombokValue.java b/src/main/java/org/openrewrite/java/migrate/lombok/UseLombokValue.java
new file mode 100644
index 0000000000..d649ffdde9
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/migrate/lombok/UseLombokValue.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.migrate.lombok;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+import org.jspecify.annotations.Nullable;
+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.JavaParser;
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.Space;
+import org.openrewrite.java.tree.Statement;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.*;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singleton;
+import static java.util.Comparator.comparing;
+import static org.openrewrite.java.tree.J.Modifier.Type.Final;
+import static org.openrewrite.java.tree.J.Modifier.Type.Private;
+import static org.openrewrite.java.tree.J.Modifier.Type.Public;
+
+@EqualsAndHashCode(callSuper = false)
+@Value
+public class UseLombokValue extends Recipe {
+
+ private static final Set CONFLICTING_LOMBOK_ANNOTATIONS = new HashSet<>(Arrays.asList(
+ "Accessors", "AllArgsConstructor", "Builder", "Data", "EqualsAndHashCode", "FieldDefaults",
+ "Getter", "NoArgsConstructor", "RequiredArgsConstructor", "Setter", "SuperBuilder",
+ "ToString", "Value"
+ ));
+
+ String displayName = "Use `@Value` where applicable";
+
+ String description = "Prefer Lombok's `@Value` annotation over boilerplate in immutable value classes.";
+
+ Set tags = singleton("lombok");
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return new JavaIsoVisitor() {
+ private final Map valueClasses = new HashMap<>();
+
+ @Override
+ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
+ ValueClass valueClass = findValueClass(classDecl);
+ if (valueClass == null) {
+ return super.visitClassDeclaration(classDecl, ctx);
+ }
+
+ valueClasses.put(classDecl.getId(), valueClass);
+ maybeAddImport("lombok.Value");
+ J.ClassDeclaration cd = JavaTemplate.builder("@Value")
+ .imports("lombok.Value")
+ .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "lombok"))
+ .build()
+ .apply(getCursor(), classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)));
+ cd = super.visitClassDeclaration(cd, ctx);
+ return cd.withModifiers(ListUtils.map(cd.getModifiers(), modifier ->
+ modifier.getType() == Final ? null : modifier));
+ }
+
+ @Override
+ public J.@Nullable MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
+ ValueClass valueClass = enclosingValueClass();
+ if (valueClass != null && valueClass.getMethodIds().contains(method.getId())) {
+ return null;
+ }
+ return super.visitMethodDeclaration(method, ctx);
+ }
+
+ @Override
+ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations variableDeclarations, ExecutionContext ctx) {
+ J.VariableDeclarations vd = super.visitVariableDeclarations(variableDeclarations, ctx);
+ ValueClass valueClass = enclosingValueClass();
+ if (valueClass != null && valueClass.getFieldIds().contains(vd.getId())) {
+ J.VariableDeclarations updated = vd.withModifiers(emptyList());
+ if (updated.getTypeExpression() != null) {
+ updated = updated.withTypeExpression(updated.getTypeExpression().withPrefix(Space.EMPTY));
+ }
+ return updated;
+ }
+ return vd;
+ }
+
+ private @Nullable ValueClass enclosingValueClass() {
+ J.ClassDeclaration enclosing = getCursor().firstEnclosing(J.ClassDeclaration.class);
+ return enclosing == null ? null : valueClasses.get(enclosing.getId());
+ }
+ };
+ }
+
+ private static @Nullable ValueClass findValueClass(J.ClassDeclaration classDecl) {
+ if (classDecl.getType() == null ||
+ !classDecl.hasModifier(Final) ||
+ hasConflictingLombokAnnotation(classDecl)) {
+ return null;
+ }
+
+ List fields = new ArrayList<>();
+ List methods = new ArrayList<>();
+ for (Statement statement : classDecl.getBody().getStatements()) {
+ if (statement instanceof J.VariableDeclarations) {
+ fields.add((J.VariableDeclarations) statement);
+ } else if (statement instanceof J.MethodDeclaration) {
+ methods.add((J.MethodDeclaration) statement);
+ }
+ }
+
+ if (fields.isEmpty() || fields.stream().anyMatch(field -> !isValueField(field))) {
+ return null;
+ }
+
+ List constructors = new ArrayList<>();
+ for (J.MethodDeclaration method : methods) {
+ if (method.isConstructor()) {
+ constructors.add(method);
+ }
+ }
+ if (constructors.size() != 1) {
+ return null;
+ }
+
+ J.MethodDeclaration constructor = constructors.get(0);
+ if (!isValueConstructor(constructor, classDecl)) {
+ return null;
+ }
+
+ Set methodIds = new HashSet<>();
+ methodIds.add(constructor.getId());
+ for (J.VariableDeclarations field : fields) {
+ for (J.VariableDeclarations.NamedVariable variable : field.getVariables()) {
+ Optional getter = findGetter(methods, variable);
+ if (!getter.isPresent()) {
+ return null;
+ }
+ methodIds.add(getter.get().getId());
+ }
+ }
+
+ if (!hasExplicitObjectMethods(methods)) {
+ return null;
+ }
+
+ Set fieldIds = new HashSet<>();
+ for (J.VariableDeclarations field : fields) {
+ fieldIds.add(field.getId());
+ }
+ return new ValueClass(fieldIds, methodIds);
+ }
+
+ private static boolean hasConflictingLombokAnnotation(J.ClassDeclaration classDecl) {
+ return classDecl.getLeadingAnnotations().stream()
+ .map(J.Annotation::getSimpleName)
+ .anyMatch(CONFLICTING_LOMBOK_ANNOTATIONS::contains);
+ }
+
+ private static boolean isValueField(J.VariableDeclarations field) {
+ if (!field.getAllAnnotations().isEmpty() ||
+ !hasOnlyModifiers(field.getModifiers(), Private, Final) ||
+ field.getVariables().isEmpty()) {
+ return false;
+ }
+ for (J.VariableDeclarations.NamedVariable variable : field.getVariables()) {
+ if (variable.getType() == null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isValueConstructor(J.MethodDeclaration constructor, J.ClassDeclaration classDecl) {
+ if (!hasOnlyModifiers(constructor.getModifiers(), Public) ||
+ !constructor.getAllAnnotations().isEmpty() ||
+ !isEmpty(constructor.getThrows()) ||
+ !isEmpty(constructor.getTypeParameters()) ||
+ hasAnnotatedOrVarargsParameters(constructor)) {
+ return false;
+ }
+ return LombokUtils.isConstructorAssigningExactFields(constructor, LombokUtils.getRequiredFields(classDecl));
+ }
+
+ private static boolean hasAnnotatedOrVarargsParameters(J.MethodDeclaration method) {
+ for (Statement parameter : method.getParameters()) {
+ if (!(parameter instanceof J.VariableDeclarations)) {
+ return true;
+ }
+ J.VariableDeclarations variableDeclarations = (J.VariableDeclarations) parameter;
+ if (!variableDeclarations.getAllAnnotations().isEmpty() || variableDeclarations.getVarargs() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static Optional findGetter(List methods,
+ J.VariableDeclarations.NamedVariable field) {
+ String getterName = LombokUtils.deriveGetterMethodName(field.getType(), field.getSimpleName());
+ List getters = new ArrayList<>();
+ for (J.MethodDeclaration method : methods) {
+ if (method.getSimpleName().equals(getterName) &&
+ LombokUtils.isGetter(method) &&
+ hasOnlyModifiers(method.getModifiers(), Public) &&
+ method.getAllAnnotations().isEmpty() &&
+ isEmpty(method.getThrows()) &&
+ isEmpty(method.getTypeParameters())) {
+ getters.add(method);
+ }
+ }
+ return getters.size() == 1 ? Optional.of(getters.get(0)) : Optional.empty();
+ }
+
+ private static boolean hasExplicitObjectMethods(List methods) {
+ boolean hasEquals = false;
+ boolean hasHashCode = false;
+ boolean hasToString = false;
+ for (J.MethodDeclaration method : methods) {
+ hasEquals |= isEquals(method);
+ hasHashCode |= isHashCode(method);
+ hasToString |= isToString(method);
+ }
+ return hasEquals && hasHashCode && hasToString;
+ }
+
+ private static boolean isEquals(J.MethodDeclaration method) {
+ if (!"equals".equals(method.getSimpleName()) ||
+ method.getType() != JavaType.Primitive.Boolean ||
+ method.getParameters().size() != 1 ||
+ !(method.getParameters().get(0) instanceof J.VariableDeclarations)) {
+ return false;
+ }
+ J.VariableDeclarations parameter = (J.VariableDeclarations) method.getParameters().get(0);
+ return parameter.getVariables().size() == 1 &&
+ isType(parameter.getVariables().get(0).getType(), "java.lang.Object");
+ }
+
+ private static boolean isHashCode(J.MethodDeclaration method) {
+ return "hashCode".equals(method.getSimpleName()) &&
+ method.getType() == JavaType.Primitive.Int &&
+ hasNoParameters(method);
+ }
+
+ private static boolean isToString(J.MethodDeclaration method) {
+ return "toString".equals(method.getSimpleName()) &&
+ isType(method.getType(), "java.lang.String") &&
+ hasNoParameters(method);
+ }
+
+ private static boolean hasNoParameters(J.MethodDeclaration method) {
+ return method.getParameters().isEmpty() ||
+ (method.getParameters().size() == 1 && method.getParameters().get(0) instanceof J.Empty);
+ }
+
+ private static boolean isEmpty(@Nullable List> values) {
+ return values == null || values.isEmpty();
+ }
+
+ private static boolean isType(@Nullable JavaType type, String fullyQualifiedName) {
+ JavaType.FullyQualified fullyQualified = TypeUtils.asFullyQualified(type);
+ return fullyQualified != null && fullyQualifiedName.equals(fullyQualified.getFullyQualifiedName());
+ }
+
+ private static boolean hasOnlyModifiers(List modifiers, J.Modifier.Type... expectedModifiers) {
+ if (modifiers.size() != expectedModifiers.length) {
+ return false;
+ }
+ Set expected = new HashSet<>(Arrays.asList(expectedModifiers));
+ return modifiers.stream().map(J.Modifier::getType).allMatch(expected::contains);
+ }
+
+ @Value
+ private static class ValueClass {
+ Set fieldIds;
+ Set methodIds;
+ }
+}
diff --git a/src/main/resources/META-INF/rewrite/lombok.yml b/src/main/resources/META-INF/rewrite/lombok.yml
index 8739fe42cd..9e2a36c16b 100644
--- a/src/main/resources/META-INF/rewrite/lombok.yml
+++ b/src/main/resources/META-INF/rewrite/lombok.yml
@@ -24,6 +24,7 @@ preconditions:
recipeList:
- org.openrewrite.java.migrate.lombok.UpdateLombokToJava11
- org.openrewrite.java.migrate.lombok.log.UseLombokLogAnnotations
+ - org.openrewrite.java.migrate.lombok.UseLombokValue
- org.openrewrite.java.migrate.lombok.UseLombokGetter
- org.openrewrite.java.migrate.lombok.UseLombokSetter
- org.openrewrite.java.migrate.lombok.UseNoArgsConstructor
diff --git a/src/main/resources/META-INF/rewrite/recipes.csv b/src/main/resources/META-INF/rewrite/recipes.csv
index dbb7a45637..547aae03b7 100644
--- a/src/main/resources/META-INF/rewrite/recipes.csv
+++ b/src/main/resources/META-INF/rewrite/recipes.csv
@@ -431,6 +431,7 @@ maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.l
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseAllArgsConstructor,Use `@AllArgsConstructor` where applicable,Prefer the Lombok `@AllArgsConstructor` annotation over explicitly written out constructors that assign all non-static fields.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseLombokGetter,Convert getter methods to annotations,Convert trivial getter methods to `@Getter` annotations on their respective fields.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseLombokSetter,Convert setter methods to annotations,Convert trivial setter methods to `@Setter` annotations on their respective fields.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
+maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseLombokValue,Use `@Value` where applicable,Prefer Lombok's `@Value` annotation over boilerplate in immutable value classes.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseNoArgsConstructor,Use `@NoArgsConstructor` where applicable,Prefer the Lombok `@NoArgsConstructor` annotation over explicitly written out constructors.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.UseRequiredArgsConstructor,Use `@RequiredArgsConstructor` where applicable,Prefer the Lombok `@RequiredArgsConstructor` annotation over explicitly written out constructors that only assign final fields.,1,,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,,
maven,org.openrewrite.recipe:rewrite-migrate-java,org.openrewrite.java.migrate.lombok.log.UseCommonsLog,Use `@CommonsLog` instead of explicit fields,Prefer the lombok annotation `@CommonsLog` over explicitly written out `org.apache.commons.logging.Log` fields.,1,Log,Lombok,Modernize,Java,,Recipes for working with [Lombok](https://projectlombok.org/).,Modernize your code to best use the project's current JDK version. Take advantage of newly available APIs and reduce the dependency of your code on third party dependencies where there is equivalent functionality in the Java standard library.,Basic building blocks for transforming Java code.,"[{""name"":""fieldName"",""type"":""String"",""displayName"":""Name of the log field"",""description"":""Name of the log field to replace. If not specified, the field name is not checked and any field that satisfies the other checks is converted."",""example"":""LOGGER""}]",
diff --git a/src/test/java/org/openrewrite/java/migrate/lombok/UseLombokValueTest.java b/src/test/java/org/openrewrite/java/migrate/lombok/UseLombokValueTest.java
new file mode 100644
index 0000000000..b8de4e735d
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/migrate/lombok/UseLombokValueTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.migrate.lombok;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.Issue;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class UseLombokValueTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new UseLombokValue());
+ }
+
+ @DocumentExample
+ @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/1046")
+ @Test
+ void replaceValueClassBoilerplate() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ public final class Person {
+ private final String name;
+ private final int age;
+
+ public Person(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Person person = (Person) o;
+ return age == person.age && name.equals(person.name);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name.hashCode();
+ return 31 * result + age;
+ }
+
+ @Override
+ public String toString() {
+ return name + age;
+ }
+ }
+ """,
+ """
+ import lombok.Value;
+
+ @Value
+ public class Person {
+ String name;
+ int age;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Person person = (Person) o;
+ return age == person.age && name.equals(person.name);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name.hashCode();
+ return 31 * result + age;
+ }
+
+ @Override
+ public String toString() {
+ return name + age;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doesNotReplaceVarargsConstructor() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ final class Person {
+ private final String[] names;
+
+ public Person(String... names) {
+ this.names = names;
+ }
+
+ public String[] getNames() {
+ return names;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Person && ((Person) o).names == names;
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(names.length);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doesNotReplaceClassWithoutAllObjectMethods() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ final class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Person && ((Person) o).name.equals(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doesNotReplaceGettersWithIncompatibleSignatures() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import java.io.IOException;
+
+ final class CheckedExceptionGetter {
+ private final String name;
+
+ public CheckedExceptionGetter(String name) {
+ this.name = name;
+ }
+
+ public String getName() throws IOException {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof CheckedExceptionGetter && ((CheckedExceptionGetter) o).name.equals(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ final class GenericGetter {
+ private final String name;
+
+ public GenericGetter(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof GenericGetter && ((GenericGetter) o).name.equals(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doesNotReplaceClassWithAccessors() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import lombok.experimental.Accessors;
+
+ @Accessors(fluent = true)
+ final class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Person && ((Person) o).name.equals(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+ """
+ )
+ );
+ }
+}