From bc097d389e29f5a6922bf172556e017272a40737 Mon Sep 17 00:00:00 2001 From: Lauriichan Date: Sun, 4 Jan 2026 15:34:31 +0100 Subject: [PATCH 1/4] Add api for static initializers --- .../forge/roaster/model/Initializer.java | 16 ++ .../roaster/model/InitializerHolder.java | 16 ++ .../jboss/forge/roaster/model/JavaClass.java | 1 + .../jboss/forge/roaster/model/JavaEnum.java | 2 +- .../jboss/forge/roaster/model/JavaRecord.java | 1 + .../model/source/InitializerHolderSource.java | 41 ++++ .../model/source/InitializerSource.java | 16 ++ .../roaster/model/source/JavaClassSource.java | 1 + .../roaster/model/source/JavaEnumSource.java | 1 + .../model/source/JavaRecordSource.java | 1 + .../roaster/model/impl/InitializerImpl.java | 176 ++++++++++++++++++ .../roaster/model/impl/JavaClassImpl.java | 47 +++++ .../roaster/model/impl/JavaEnumImpl.java | 45 ++++- .../roaster/model/impl/JavaRecordImpl.java | 44 +++++ .../roaster/model/InitializerBodyTest.java | 50 +++++ .../model/InitializerImplementationTest.java | 39 ++++ .../model/JavaClassInitializerTest.java | 45 +++++ .../model/JavaEnumInitializerTest.java | 45 +++++ .../model/JavaRecordInitializerTest.java | 40 ++++ 19 files changed, 625 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/org/jboss/forge/roaster/model/Initializer.java create mode 100644 api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java create mode 100644 api/src/main/java/org/jboss/forge/roaster/model/source/InitializerHolderSource.java create mode 100644 api/src/main/java/org/jboss/forge/roaster/model/source/InitializerSource.java create mode 100644 impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java create mode 100644 tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerBodyTest.java create mode 100644 tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerImplementationTest.java create mode 100644 tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java create mode 100644 tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java create mode 100644 tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java diff --git a/api/src/main/java/org/jboss/forge/roaster/model/Initializer.java b/api/src/main/java/org/jboss/forge/roaster/model/Initializer.java new file mode 100644 index 00000000..b8dfcaef --- /dev/null +++ b/api/src/main/java/org/jboss/forge/roaster/model/Initializer.java @@ -0,0 +1,16 @@ +package org.jboss.forge.roaster.model; + +import org.jboss.forge.roaster.Internal; +import org.jboss.forge.roaster.Origin; + +/** + * Represents a initializer of a {@link JavaClass}, {@link JavaRecord} or {@link JavaEnum}. + */ +public interface Initializer, T extends Initializer> extends StaticCapable, Internal, Origin { + + /** + * Get the inner body of this {@link Initializer} + */ + String getBody(); + +} diff --git a/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java b/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java new file mode 100644 index 00000000..fb8b6d42 --- /dev/null +++ b/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java @@ -0,0 +1,16 @@ +package org.jboss.forge.roaster.model; + +import java.util.List; + +/** + * Represents a {@link JavaType} that may define initializers. + */ +public interface InitializerHolder> { + + /** + * Get a {@link List} of all {@link Initializer}s declared by this {@link O} instance, if any; otherwise return an empty + * {@link List} + */ + List> getInitializers(); + +} diff --git a/api/src/main/java/org/jboss/forge/roaster/model/JavaClass.java b/api/src/main/java/org/jboss/forge/roaster/model/JavaClass.java index 5d9e4513..2745d9f8 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/JavaClass.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/JavaClass.java @@ -18,6 +18,7 @@ public interface JavaClass> extends JavaType, PropertyHolder, + InitializerHolder, GenericCapable, Extendable, Abstractable, diff --git a/api/src/main/java/org/jboss/forge/roaster/model/JavaEnum.java b/api/src/main/java/org/jboss/forge/roaster/model/JavaEnum.java index 4a3f6dff..0b1dfb26 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/JavaEnum.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/JavaEnum.java @@ -17,7 +17,7 @@ * * @author Lincoln Baxter, III */ -public interface JavaEnum> extends JavaType, PropertyHolder, TypeHolder, StaticCapable +public interface JavaEnum> extends JavaType, PropertyHolder, InitializerHolder, TypeHolder, StaticCapable { /** * Return the {@link EnumConstant} with the given name, or return null if no such constant exists. diff --git a/api/src/main/java/org/jboss/forge/roaster/model/JavaRecord.java b/api/src/main/java/org/jboss/forge/roaster/model/JavaRecord.java index fd29a64a..d87a1d77 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/JavaRecord.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/JavaRecord.java @@ -11,6 +11,7 @@ public interface JavaRecord> extends JavaType, MethodHolder, + InitializerHolder, TypeHolder, InterfaceCapable { diff --git a/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerHolderSource.java b/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerHolderSource.java new file mode 100644 index 00000000..55028852 --- /dev/null +++ b/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerHolderSource.java @@ -0,0 +1,41 @@ +package org.jboss.forge.roaster.model.source; + +import java.util.List; + +import org.jboss.forge.roaster.model.Initializer; +import org.jboss.forge.roaster.model.InitializerHolder; + +/** + * Represents a {@link JavaSource} that may declare initializers. + */ +public interface InitializerHolderSource> extends InitializerHolder, MemberHolderSource { + + /** + * Get a {@link List} of all {@link InitializerSource}s declared by this {@link O} instance, if any; otherwise return an + * empty {@link List} + */ + @Override + List> getInitializers(); + + /** + * Add an uninitialized {@link InitializerSource} declaration to this {@link O} instance. This {@link InitializerSource} will + * be a stub until further modified. + */ + InitializerSource addInitializer(); + + /** + * Add a new {@link InitializerSource} declaration to this {@link O} instance, using the given {@link String} as the + * initializer declaration. + *

+ * For example:
+ * Initializer initializer = javaClass.addInitializer("static { System.out.println(\"Hello\") }") + */ + InitializerSource addInitializer(final String body); + + /** + * Remove the given {@link InitializerSource} declaration from this {@link O} instance, if it exists; otherwise, do + * nothing. + */ + O removeInitializer(final Initializer initializer); + +} diff --git a/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerSource.java b/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerSource.java new file mode 100644 index 00000000..9b16d444 --- /dev/null +++ b/api/src/main/java/org/jboss/forge/roaster/model/source/InitializerSource.java @@ -0,0 +1,16 @@ +package org.jboss.forge.roaster.model.source; + +import org.jboss.forge.roaster.model.Initializer; + +/** + * Represents a Java initializer in source form. + */ +public interface InitializerSource> extends Initializer>, + JavaDocCapableSource>, StaticCapableSource>, LocationCapable { + + /** + * Set the inner body of this {@link Initializer} + */ + InitializerSource setBody(String body); + +} diff --git a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaClassSource.java b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaClassSource.java index 9d02ca63..3f8858ee 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaClassSource.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaClassSource.java @@ -22,6 +22,7 @@ public interface JavaClassSource extends JavaClass, GenericCapableSource, ExtendableSource, AbstractableSource, + InitializerHolderSource, PropertyHolderSource, TypeHolderSource, FinalCapableSource, diff --git a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaEnumSource.java b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaEnumSource.java index 7b342946..c96ebe77 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaEnumSource.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaEnumSource.java @@ -21,6 +21,7 @@ */ public interface JavaEnumSource extends JavaEnum, JavaSource, InterfaceCapableSource, + InitializerHolderSource, PropertyHolderSource, TypeHolderSource, StaticCapableSource { /** diff --git a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaRecordSource.java b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaRecordSource.java index 3e659934..1c59b557 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/source/JavaRecordSource.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/source/JavaRecordSource.java @@ -9,6 +9,7 @@ public interface JavaRecordSource extends JavaSource, JavaRecord, MethodHolderSource, + InitializerHolderSource, TypeHolderSource, InterfaceCapableSource { diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java new file mode 100644 index 00000000..28c30b26 --- /dev/null +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java @@ -0,0 +1,176 @@ +package org.jboss.forge.roaster.model.impl; + +import java.util.List; + +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.jboss.forge.roaster.ParserException; +import org.jboss.forge.roaster.Problem; +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.ast.ModifierAccessor; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.jboss.forge.roaster.model.source.JavaDocSource; +import org.jboss.forge.roaster.model.source.JavaSource; +import org.jboss.forge.roaster.model.util.JDTOptions; + +public class InitializerImpl> implements InitializerSource +{ + private final ModifierAccessor modifiers = new ModifierAccessor(); + + private O parent = null; + private AST ast = null; + private CompilationUnit cu = null; + private final Initializer initializer; + + private void init(final O parent) + { + this.parent = parent; + cu = (CompilationUnit) parent.getInternal(); + ast = cu.getAST(); + } + + public InitializerImpl(final O parent) + { + init(parent); + initializer = ast.newInitializer(); + } + + public InitializerImpl(final O parent, final Object internal) + { + init(parent); + initializer = (Initializer) internal; + } + + public InitializerImpl(final O parent, final String initializer) + { + init(parent); + String stub = "public class Stub { " + initializer + " }"; + JavaClassSource temp = (JavaClassSource) Roaster.parse(stub); + Initializer newInitializer = (Initializer) temp.getInitializers().get(0).getInternal(); + this.initializer = (Initializer) ASTNode.copySubtree(cu.getAST(), newInitializer); + } + + @Override + public String getBody() + { + Block body = initializer.getBody(); + if (body != null) + { + StringBuilder result = new StringBuilder(); + List statements = (List) body.getStructuralProperty(Block.STATEMENTS_PROPERTY); + for (Statement statement : statements) { + result.append(statement).append(" "); + } + return result.toString().trim(); + } + return null; + } + + @Override + public InitializerSource setBody(String body) + { + if (body == null) { + initializer.setBody(null); + return this; + } + List problems = Roaster.validateSnippet(body); + if (problems.size() > 0) { + throw new ParserException(problems); + } + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setSource(body.toCharArray()); + parser.setCompilerOptions(JDTOptions.getJDTOptions()); + parser.setKind(ASTParser.K_STATEMENTS); + Block block = (Block) parser.createAST(null); + block = (Block) ASTNode.copySubtree(initializer.getAST(), block); + initializer.setBody(block); + return this; + } + + @Override + public boolean isStatic() + { + return modifiers.hasModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + } + + @Override + public InitializerSource setStatic(boolean statc) + { + if (statc) + modifiers.addModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + else + modifiers.removeModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + return this; + } + + @Override + public Object getInternal() + { + return initializer; + } + + @Override + public O getOrigin() + { + return parent; + } + + @Override + public boolean hasJavaDoc() + { + return initializer.getJavadoc() != null; + } + + @Override + public InitializerSource removeJavaDoc() + { + initializer.setJavadoc(null); + return this; + } + + @Override + public JavaDocSource> getJavaDoc() + { + Javadoc javadoc = initializer.getJavadoc(); + if (javadoc == null) + { + javadoc = initializer.getAST().newJavadoc(); + initializer.setJavadoc(javadoc); + } + return new JavaDocImpl<>(this, javadoc); + } + + @Override + public int getStartPosition() + { + return initializer.getStartPosition(); + } + + @Override + public int getEndPosition() + { + int startPosition = getStartPosition(); + return (startPosition == -1) ? -1 : startPosition + initializer.getLength(); + } + + @Override + public int getLineNumber() + { + return cu.getLineNumber(getStartPosition()); + } + + @Override + public int getColumnNumber() + { + return cu.getColumnNumber(getStartPosition()); + } + +} diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java index d866513d..15565d2c 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java @@ -6,8 +6,13 @@ */ package org.jboss.forge.roaster.model.impl; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.SimpleName; @@ -18,6 +23,7 @@ import org.jboss.forge.roaster.model.JavaType; import org.jboss.forge.roaster.model.ast.ModifierAccessor; import org.jboss.forge.roaster.model.source.Import; +import org.jboss.forge.roaster.model.source.InitializerSource; import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.JavaSource; import org.jboss.forge.roaster.model.source.MethodSource; @@ -245,4 +251,45 @@ private boolean handleNullSuperType(Object type) } return false; } + + @Override + @SuppressWarnings("unchecked") + public List> getInitializers() + { + List> result = new ArrayList<>(); + List bodyDeclarations = getDeclaration().bodyDeclarations(); + for (BodyDeclaration bodyDeclaration : bodyDeclarations) + { + if (bodyDeclaration instanceof Initializer) { + Initializer initializer = (Initializer) bodyDeclaration; + result.add(new InitializerImpl<>(this, initializer)); + } + } + return Collections.unmodifiableList(result); + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer() + { + InitializerSource init = new InitializerImpl<>(this); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer(final String initializer) + { + InitializerSource init = new InitializerImpl<>(this, initializer); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + public JavaClassSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) + { + getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + return this; + } } \ No newline at end of file diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java index e1254d73..590d68d0 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java @@ -14,8 +14,10 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jface.text.Document; import org.jboss.forge.roaster.model.source.EnumConstantSource; +import org.jboss.forge.roaster.model.source.InitializerSource; import org.jboss.forge.roaster.model.source.JavaEnumSource; import org.jboss.forge.roaster.model.source.JavaSource; @@ -24,7 +26,7 @@ * * @author Lincoln Baxter, III */ -public class JavaEnumImpl extends AbstractJavaSourceMemberHolderimplements JavaEnumSource +public class JavaEnumImpl extends AbstractJavaSourceMemberHolder implements JavaEnumSource { public JavaEnumImpl(JavaSource enclosingType, final Document document, final CompilationUnit unit, BodyDeclaration body) @@ -90,4 +92,45 @@ protected JavaEnumSource updateTypeNames(final String newName) return this; } + @Override + @SuppressWarnings("unchecked") + public List> getInitializers() + { + List> result = new ArrayList<>(); + List bodyDeclarations = getDeclaration().bodyDeclarations(); + for (BodyDeclaration bodyDeclaration : bodyDeclarations) + { + if (bodyDeclaration instanceof Initializer) { + Initializer initializer = (Initializer) bodyDeclaration; + result.add(new InitializerImpl<>(this, initializer)); + } + } + return Collections.unmodifiableList(result); + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer() + { + InitializerSource init = new InitializerImpl<>(this); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer(final String initializer) + { + InitializerSource init = new InitializerImpl<>(this, initializer); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + public JavaEnumSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) + { + getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + return this; + } + } diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java index 7dcb4904..f545e4cc 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java @@ -7,7 +7,9 @@ package org.jboss.forge.roaster.model.impl; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.RecordDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; @@ -19,6 +21,7 @@ import org.jboss.forge.roaster.model.Type; import org.jboss.forge.roaster.model.ast.MethodFinderVisitor; import org.jboss.forge.roaster.model.source.Import; +import org.jboss.forge.roaster.model.source.InitializerSource; import org.jboss.forge.roaster.model.source.InterfaceCapableSource; import org.jboss.forge.roaster.model.source.JavaRecordComponentSource; import org.jboss.forge.roaster.model.source.JavaRecordSource; @@ -121,4 +124,45 @@ public JavaRecordSource removeRecordComponent(JavaRecordComponent recordComponen getDeclaration().recordComponents().remove(recordComponent.getInternal()); return this; } + + @Override + @SuppressWarnings("unchecked") + public List> getInitializers() + { + List> result = new ArrayList<>(); + List bodyDeclarations = getDeclaration().bodyDeclarations(); + for (BodyDeclaration bodyDeclaration : bodyDeclarations) + { + if (bodyDeclaration instanceof Initializer) { + Initializer initializer = (Initializer) bodyDeclaration; + result.add(new InitializerImpl<>(this, initializer)); + } + } + return Collections.unmodifiableList(result); + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer() + { + InitializerSource init = new InitializerImpl<>(this); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + @SuppressWarnings("unchecked") + public InitializerSource addInitializer(final String initializer) + { + InitializerSource init = new InitializerImpl<>(this, initializer); + getDeclaration().bodyDeclarations().add(init.getInternal()); + return init; + } + + @Override + public JavaRecordSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) + { + getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + return this; + } } diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerBodyTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerBodyTest.java new file mode 100644 index 00000000..8b9f5d83 --- /dev/null +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerBodyTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Eclipse Public License version 1.0, available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.jboss.forge.test.roaster.model; + +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * Test for initializer bodies + */ +public class InitializerBodyTest +{ + @Test + public void testSetInitializerBody() + { + String body = "System.out.println(\"Hello world!\");"; + JavaClassSource source = Roaster.create(JavaClassSource.class); + InitializerSource initializer = source.addInitializer().setBody(body); + assertEquals(body, initializer.getBody()); + } + + @Test + public void testInitializerBodyWithLambdas() + { + String body = "foo((c) -> System.out::println);"; + JavaClassSource source = Roaster.create(JavaClassSource.class); + InitializerSource method = source.addInitializer().setBody(body); + assertEquals(body, method.getBody()); + } + + @Test + public void testBodyShouldBeSet() + { + JavaClassSource javaClass = Roaster.create(JavaClassSource.class); + InitializerSource initializer = javaClass.addInitializer() + .setBody("OpenIabHelper.Options.Builder builder = new OpenIabHelper.Options.Builder(); \n\t builder.setStoreSearchStrategy(OpenIabHelper.Options.SEARCH_STRATEGY_INSTALLER);"); + assertNotNull(initializer.getBody()); + assertThat(initializer.getBody()).isNotEmpty(); + } +} \ No newline at end of file diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerImplementationTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerImplementationTest.java new file mode 100644 index 00000000..497a799f --- /dev/null +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/InitializerImplementationTest.java @@ -0,0 +1,39 @@ +package org.jboss.forge.test.roaster.model; + +import org.jboss.forge.roaster.ParserException; +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class InitializerImplementationTest +{ + + @Test + public void testInitializerBodyShouldNotBeEmptyOnInvalidCode() { + JavaClassSource source = Roaster.create(JavaClassSource.class); + InitializerSource initializer = source.addInitializer(); + assertThrows(ParserException.class, () -> initializer.setBody("{}{{}{dasfasdfasdfga")); + } + + @Test + public void testEmptyInitializerBodyShouldNotThrowException() { + JavaClassSource source = Roaster.create(JavaClassSource.class); + InitializerSource initializer = source.addInitializer(); + initializer.setBody(""); + assertEquals("", initializer.getBody()); + } + + @Test + public void testInitializerBodyShouldParseCorrectly() + { + JavaClassSource source = Roaster.create(JavaClassSource.class); + InitializerSource initializer = source.addInitializer(); + initializer.setBody("System.out.println(\"Hello world!\");"); + assertEquals("System.out.println(\"Hello world!\");", initializer.getBody()); + } + +} diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java new file mode 100644 index 00000000..980c5ab1 --- /dev/null +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java @@ -0,0 +1,45 @@ +package org.jboss.forge.test.roaster.model; + +import java.io.IOException; +import java.io.InputStream; + +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaClassSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavaClassInitializerTest +{ + + private JavaClassSource javaClass; + private InitializerSource initializer; + + @BeforeEach + public void reset() throws IOException + { + String fileName = "/org/jboss/forge/grammar/java/MockClass.java"; + try (InputStream stream = JavaEnumMethodTest.class.getResourceAsStream(fileName)) + { + javaClass = Roaster.parse(JavaClassSource.class, stream); + javaClass.addInitializer("{ System.out.println(\"Hello world!\") }"); + initializer = javaClass.getInitializers().get(javaClass.getInitializers().size() - 1); + } + } + + @Test + public void testIsNonStatic() { + assertFalse(initializer.isStatic()); + } + + @Test + public void testSetStatic() { + assertFalse(initializer.isStatic()); + initializer.setStatic(true); + assertTrue(initializer.isStatic()); + } + +} diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java new file mode 100644 index 00000000..da58902e --- /dev/null +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java @@ -0,0 +1,45 @@ +package org.jboss.forge.test.roaster.model; + +import java.io.IOException; +import java.io.InputStream; + +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaEnumSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavaEnumInitializerTest +{ + + private JavaEnumSource javaEnum; + private InitializerSource initializer; + + @BeforeEach + public void reset() throws IOException + { + String fileName = "/org/jboss/forge/grammar/java/MockEnum.java"; + try (InputStream stream = JavaEnumMethodTest.class.getResourceAsStream(fileName)) + { + javaEnum = Roaster.parse(JavaEnumSource.class, stream); + javaEnum.addInitializer("{ System.out.println(\"Hello world!\") }"); + initializer = javaEnum.getInitializers().get(javaEnum.getInitializers().size() - 1); + } + } + + @Test + public void testIsNonStatic() { + assertFalse(initializer.isStatic()); + } + + @Test + public void testSetStatic() { + assertFalse(initializer.isStatic()); + initializer.setStatic(true); + assertTrue(initializer.isStatic()); + } + +} diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java new file mode 100644 index 00000000..46400517 --- /dev/null +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java @@ -0,0 +1,40 @@ +package org.jboss.forge.test.roaster.model; + +import java.io.IOException; + +import org.jboss.forge.roaster.Roaster; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaRecordSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JavaRecordInitializerTest +{ + + private JavaRecordSource javaRecord; + private InitializerSource initializer; + + @BeforeEach + public void reset() throws IOException + { + javaRecord = Roaster.parse(JavaRecordSource.class, "public record MockRecord(int foo, String bar) {}"); + javaRecord.addInitializer("{ System.out.println(\"Hello world!\") }"); + initializer = javaRecord.getInitializers().get(javaRecord.getInitializers().size() - 1); + } + + @Test + public void testIsNonStatic() { + assertFalse(initializer.isStatic()); + } + + @Test + public void testSetStatic() { + assertFalse(initializer.isStatic()); + initializer.setStatic(true); + assertTrue(initializer.isStatic()); + } + +} From 531b84ff9d2c0eeddd4bb5978c73b914768d1045 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Sun, 4 Jan 2026 20:37:20 -0300 Subject: [PATCH 2/4] Update modifier handling in InitializerImpl As introduced in https://github.com/forge/roaster/pull/387 --- .../jboss/forge/roaster/model/impl/InitializerImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java index 28c30b26..d20ce827 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java @@ -23,8 +23,6 @@ public class InitializerImpl> implements InitializerSource { - private final ModifierAccessor modifiers = new ModifierAccessor(); - private O parent = null; private AST ast = null; private CompilationUnit cu = null; @@ -98,16 +96,16 @@ public InitializerSource setBody(String body) @Override public boolean isStatic() { - return modifiers.hasModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + return ModifierAccessor.hasModifier(initializer, ModifierKeyword.STATIC_KEYWORD); } @Override public InitializerSource setStatic(boolean statc) { if (statc) - modifiers.addModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + ModifierAccessor.addModifier(initializer, ModifierKeyword.STATIC_KEYWORD); else - modifiers.removeModifier(initializer, ModifierKeyword.STATIC_KEYWORD); + ModifierAccessor.removeModifier(initializer, ModifierKeyword.STATIC_KEYWORD); return this; } From 7f675a5ea26a0df2d572e85ea736f017a82b7a13 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Sun, 4 Jan 2026 20:39:20 -0300 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../forge/test/roaster/model/JavaClassInitializerTest.java | 2 +- .../jboss/forge/test/roaster/model/JavaEnumInitializerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java index 980c5ab1..159a8c3d 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java @@ -22,7 +22,7 @@ public class JavaClassInitializerTest public void reset() throws IOException { String fileName = "/org/jboss/forge/grammar/java/MockClass.java"; - try (InputStream stream = JavaEnumMethodTest.class.getResourceAsStream(fileName)) + try (InputStream stream = JavaClassInitializerTest.class.getResourceAsStream(fileName)) { javaClass = Roaster.parse(JavaClassSource.class, stream); javaClass.addInitializer("{ System.out.println(\"Hello world!\") }"); diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java index da58902e..09244564 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java @@ -22,7 +22,7 @@ public class JavaEnumInitializerTest public void reset() throws IOException { String fileName = "/org/jboss/forge/grammar/java/MockEnum.java"; - try (InputStream stream = JavaEnumMethodTest.class.getResourceAsStream(fileName)) + try (InputStream stream = JavaEnumInitializerTest.class.getResourceAsStream(fileName)) { javaEnum = Roaster.parse(JavaEnumSource.class, stream); javaEnum.addInitializer("{ System.out.println(\"Hello world!\") }"); From 668bb2962267184fc746a9d4035f7a2578feb0c4 Mon Sep 17 00:00:00 2001 From: Lauriichan Date: Mon, 5 Jan 2026 10:51:10 +0100 Subject: [PATCH 4/4] Add more tests, extract common code and add equals/hashCode to init. --- .../roaster/model/InitializerHolder.java | 5 ++ .../model/ast/InitializerAccessor.java | 65 +++++++++++++++++++ .../roaster/model/impl/InitializerImpl.java | 39 +++++++++++ .../roaster/model/impl/JavaClassImpl.java | 35 ++++------ .../roaster/model/impl/JavaEnumImpl.java | 33 ++++------ .../roaster/model/impl/JavaRecordImpl.java | 41 ++++-------- .../model/JavaClassInitializerTest.java | 20 ++++++ .../forge/test/roaster/model/JavaDocTest.java | 19 ++++++ .../model/JavaEnumInitializerTest.java | 20 ++++++ .../model/JavaRecordInitializerTest.java | 22 ++++++- .../jboss/forge/grammar/java/MockClass.java | 8 +++ .../jboss/forge/grammar/java/MockEnum.java | 8 +++ 12 files changed, 241 insertions(+), 74 deletions(-) create mode 100644 impl/src/main/java/org/jboss/forge/roaster/model/ast/InitializerAccessor.java diff --git a/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java b/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java index fb8b6d42..5b467313 100644 --- a/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java +++ b/api/src/main/java/org/jboss/forge/roaster/model/InitializerHolder.java @@ -13,4 +13,9 @@ public interface InitializerHolder> { */ List> getInitializers(); + /** + * Return true if this {@link O} instance has the provided {@link Initializer}; otherwise false. + */ + boolean hasInitializer(Initializer initializer); + } diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/ast/InitializerAccessor.java b/impl/src/main/java/org/jboss/forge/roaster/model/ast/InitializerAccessor.java new file mode 100644 index 00000000..50d7da55 --- /dev/null +++ b/impl/src/main/java/org/jboss/forge/roaster/model/ast/InitializerAccessor.java @@ -0,0 +1,65 @@ +package org.jboss.forge.roaster.model.ast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.Initializer; +import org.jboss.forge.roaster.model.impl.InitializerImpl; +import org.jboss.forge.roaster.model.source.InitializerSource; +import org.jboss.forge.roaster.model.source.JavaSource; + +public final class InitializerAccessor +{ + + @SuppressWarnings("unchecked") + public static > List> getInitializers(O origin, + AbstractTypeDeclaration declaration) + { + + List> result = new ArrayList<>(); + List bodyDeclarations = declaration.bodyDeclarations(); + for (BodyDeclaration bodyDeclaration : bodyDeclarations) + { + if (bodyDeclaration instanceof Initializer) + { + Initializer initializer = (Initializer) bodyDeclaration; + result.add(new InitializerImpl<>(origin, initializer)); + } + } + return Collections.unmodifiableList(result); + } + + public static > boolean hasInitializer(AbstractTypeDeclaration declaration, + org.jboss.forge.roaster.model.Initializer initializer) + { + return declaration.bodyDeclarations().contains(initializer.getInternal()); + } + + @SuppressWarnings("unchecked") + public static > InitializerSource addInitializer(O origin, + AbstractTypeDeclaration declaration) + { + InitializerImpl init = new InitializerImpl<>(origin); + declaration.bodyDeclarations().add(init.getInternal()); + return init; + } + + @SuppressWarnings("unchecked") + public static > InitializerSource addInitializer(O origin, + AbstractTypeDeclaration declaration, String initializer) + { + InitializerImpl init = new InitializerImpl<>(origin, initializer); + declaration.bodyDeclarations().add(init.getInternal()); + return init; + } + + public static void removeInitializer(AbstractTypeDeclaration declaration, + org.jboss.forge.roaster.model.Initializer initializer) + { + declaration.bodyDeclarations().remove(initializer.getInternal()); + } + +} diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java index d20ce827..ee2b4447 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/InitializerImpl.java @@ -120,6 +120,45 @@ public O getOrigin() { return parent; } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = (prime * result) + ((initializer == null) ? 0 : initializer.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + InitializerImpl other = (InitializerImpl) obj; + if (initializer == null) + { + if (other.initializer != null) + { + return false; + } + } + else if (!initializer.equals(other.initializer)) + { + return false; + } + return true; + } @Override public boolean hasJavaDoc() diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java index 116bb8a0..a540a831 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaClassImpl.java @@ -6,21 +6,20 @@ */ package org.jboss.forge.roaster.model.impl; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jface.text.Document; +import org.jboss.forge.roaster.model.Initializer; import org.jboss.forge.roaster.model.JavaClass; import org.jboss.forge.roaster.model.JavaType; +import org.jboss.forge.roaster.model.ast.InitializerAccessor; import org.jboss.forge.roaster.model.ast.ModifierAccessor; import org.jboss.forge.roaster.model.source.Import; import org.jboss.forge.roaster.model.source.InitializerSource; @@ -252,43 +251,33 @@ private boolean handleNullSuperType(Object type) } @Override - @SuppressWarnings("unchecked") public List> getInitializers() { - List> result = new ArrayList<>(); - List bodyDeclarations = getDeclaration().bodyDeclarations(); - for (BodyDeclaration bodyDeclaration : bodyDeclarations) - { - if (bodyDeclaration instanceof Initializer) { - Initializer initializer = (Initializer) bodyDeclaration; - result.add(new InitializerImpl<>(this, initializer)); - } - } - return Collections.unmodifiableList(result); + return InitializerAccessor.getInitializers(this, getDeclaration()); + } + + @Override + public boolean hasInitializer(Initializer initializer) + { + return InitializerAccessor.hasInitializer(getDeclaration(), initializer); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer() { - InitializerSource init = new InitializerImpl<>(this); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration()); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer(final String initializer) { - InitializerSource init = new InitializerImpl<>(this, initializer); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration(), initializer); } @Override public JavaClassSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) { - getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + InitializerAccessor.removeInitializer(getDeclaration(), initializer); return this; } } \ No newline at end of file diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java index 590d68d0..4869e07d 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaEnumImpl.java @@ -14,8 +14,9 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.jdt.core.dom.EnumDeclaration; -import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jface.text.Document; +import org.jboss.forge.roaster.model.Initializer; +import org.jboss.forge.roaster.model.ast.InitializerAccessor; import org.jboss.forge.roaster.model.source.EnumConstantSource; import org.jboss.forge.roaster.model.source.InitializerSource; import org.jboss.forge.roaster.model.source.JavaEnumSource; @@ -93,43 +94,33 @@ protected JavaEnumSource updateTypeNames(final String newName) } @Override - @SuppressWarnings("unchecked") public List> getInitializers() { - List> result = new ArrayList<>(); - List bodyDeclarations = getDeclaration().bodyDeclarations(); - for (BodyDeclaration bodyDeclaration : bodyDeclarations) - { - if (bodyDeclaration instanceof Initializer) { - Initializer initializer = (Initializer) bodyDeclaration; - result.add(new InitializerImpl<>(this, initializer)); - } - } - return Collections.unmodifiableList(result); + return InitializerAccessor.getInitializers(this, getDeclaration()); + } + + @Override + public boolean hasInitializer(Initializer initializer) + { + return InitializerAccessor.hasInitializer(getDeclaration(), initializer); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer() { - InitializerSource init = new InitializerImpl<>(this); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration()); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer(final String initializer) { - InitializerSource init = new InitializerImpl<>(this, initializer); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration(), initializer); } @Override public JavaEnumSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) { - getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + InitializerAccessor.removeInitializer(getDeclaration(), initializer); return this; } diff --git a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java index f545e4cc..27ad1a17 100644 --- a/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java +++ b/impl/src/main/java/org/jboss/forge/roaster/model/impl/JavaRecordImpl.java @@ -7,31 +7,24 @@ package org.jboss.forge.roaster.model.impl; import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Initializer; -import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.RecordDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jface.text.Document; import org.jboss.forge.roaster.Roaster; -import org.jboss.forge.roaster.model.JavaInterface; +import org.jboss.forge.roaster.model.Initializer; import org.jboss.forge.roaster.model.JavaRecordComponent; -import org.jboss.forge.roaster.model.Method; import org.jboss.forge.roaster.model.Type; -import org.jboss.forge.roaster.model.ast.MethodFinderVisitor; +import org.jboss.forge.roaster.model.ast.InitializerAccessor; import org.jboss.forge.roaster.model.source.Import; import org.jboss.forge.roaster.model.source.InitializerSource; -import org.jboss.forge.roaster.model.source.InterfaceCapableSource; import org.jboss.forge.roaster.model.source.JavaRecordComponentSource; import org.jboss.forge.roaster.model.source.JavaRecordSource; import org.jboss.forge.roaster.model.source.JavaSource; import org.jboss.forge.roaster.model.source.MemberSource; -import org.jboss.forge.roaster.model.source.MethodSource; import org.jboss.forge.roaster.model.util.Types; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -126,43 +119,33 @@ public JavaRecordSource removeRecordComponent(JavaRecordComponent recordComponen } @Override - @SuppressWarnings("unchecked") public List> getInitializers() { - List> result = new ArrayList<>(); - List bodyDeclarations = getDeclaration().bodyDeclarations(); - for (BodyDeclaration bodyDeclaration : bodyDeclarations) - { - if (bodyDeclaration instanceof Initializer) { - Initializer initializer = (Initializer) bodyDeclaration; - result.add(new InitializerImpl<>(this, initializer)); - } - } - return Collections.unmodifiableList(result); + return InitializerAccessor.getInitializers(this, getDeclaration()); + } + + @Override + public boolean hasInitializer(Initializer initializer) + { + return InitializerAccessor.hasInitializer(getDeclaration(), initializer); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer() { - InitializerSource init = new InitializerImpl<>(this); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration()); } @Override - @SuppressWarnings("unchecked") public InitializerSource addInitializer(final String initializer) { - InitializerSource init = new InitializerImpl<>(this, initializer); - getDeclaration().bodyDeclarations().add(init.getInternal()); - return init; + return InitializerAccessor.addInitializer(this, getDeclaration(), initializer); } @Override public JavaRecordSource removeInitializer(org.jboss.forge.roaster.model.Initializer initializer) { - getDeclaration().bodyDeclarations().remove(initializer.getInternal()); + InitializerAccessor.removeInitializer(getDeclaration(), initializer); return this; } } diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java index 159a8c3d..7c42165e 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaClassInitializerTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -41,5 +42,24 @@ public void testSetStatic() { initializer.setStatic(true); assertTrue(initializer.isStatic()); } + + @Test + public void testGetInitializers() { + assertEquals(3, javaClass.getInitializers().size()); + } + + @Test + public void testRemoveInitializer() { + assertTrue(javaClass.hasInitializer(initializer)); + javaClass.removeInitializer(initializer); + assertFalse(javaClass.hasInitializer(initializer)); + } + + @Test + public void testAddInitializer() { + assertEquals(3, javaClass.getInitializers().size()); + javaClass.addInitializer(); + assertEquals(4, javaClass.getInitializers().size()); + } } diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaDocTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaDocTest.java index 262d4577..6c0586ef 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaDocTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaDocTest.java @@ -12,6 +12,7 @@ import org.jboss.forge.roaster.model.JavaDocTag; import org.jboss.forge.roaster.model.source.EnumConstantSource; import org.jboss.forge.roaster.model.source.FieldSource; +import org.jboss.forge.roaster.model.source.InitializerSource; import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.JavaDocSource; import org.jboss.forge.roaster.model.source.JavaEnumSource; @@ -154,6 +155,24 @@ public void testJavaDocMethod() assertEquals(expected, javaDoc.getFullText()); } + @Test + public void testJavaDocInitializer() + { + String text = "public class MyClass {" + + "/**" + LINE_SEPARATOR + + " * Do Something" + LINE_SEPARATOR + + " * @author George Gastaldi" + LINE_SEPARATOR + " */" + LINE_SEPARATOR + "" + + "{};}"; + JavaClassSource javaClass = Roaster.parse(JavaClassSource.class, text); + assertFalse(javaClass.hasJavaDoc()); + assertEquals(1, javaClass.getInitializers().size()); + InitializerSource initializer = javaClass.getInitializers().get(0); + assertTrue(initializer.hasJavaDoc()); + JavaDocSource> javaDoc = initializer.getJavaDoc(); + String expected = "Do Something" + LINE_SEPARATOR + "@author George Gastaldi"; + assertEquals(expected, javaDoc.getFullText()); + } + @Test public void testJavaDocEnumConstant() { diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java index 09244564..9495ddc7 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaEnumInitializerTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -41,5 +42,24 @@ public void testSetStatic() { initializer.setStatic(true); assertTrue(initializer.isStatic()); } + + @Test + public void testGetInitializers() { + assertEquals(3, javaEnum.getInitializers().size()); + } + + @Test + public void testRemoveInitializer() { + assertTrue(javaEnum.hasInitializer(initializer)); + javaEnum.removeInitializer(initializer); + assertFalse(javaEnum.hasInitializer(initializer)); + } + + @Test + public void testAddInitializer() { + assertEquals(3, javaEnum.getInitializers().size()); + javaEnum.addInitializer(); + assertEquals(4, javaEnum.getInitializers().size()); + } } diff --git a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java index 46400517..69acef04 100644 --- a/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java +++ b/tests/src/test/java/org/jboss/forge/test/roaster/model/JavaRecordInitializerTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -20,7 +21,7 @@ public class JavaRecordInitializerTest @BeforeEach public void reset() throws IOException { - javaRecord = Roaster.parse(JavaRecordSource.class, "public record MockRecord(int foo, String bar) {}"); + javaRecord = Roaster.parse(JavaRecordSource.class, "public record MockRecord(int foo, String bar) { { System.out.println(\"Hello world!\") } \n static { System.out.println(\"Hello world!\") } }"); javaRecord.addInitializer("{ System.out.println(\"Hello world!\") }"); initializer = javaRecord.getInitializers().get(javaRecord.getInitializers().size() - 1); } @@ -36,5 +37,24 @@ public void testSetStatic() { initializer.setStatic(true); assertTrue(initializer.isStatic()); } + + @Test + public void testGetInitializers() { + assertEquals(3, javaRecord.getInitializers().size()); + } + + @Test + public void testRemoveInitializer() { + assertTrue(javaRecord.hasInitializer(initializer)); + javaRecord.removeInitializer(initializer); + assertFalse(javaRecord.hasInitializer(initializer)); + } + + @Test + public void testAddInitializer() { + assertEquals(3, javaRecord.getInitializers().size()); + javaRecord.addInitializer(); + assertEquals(4, javaRecord.getInitializers().size()); + } } diff --git a/tests/src/test/resources/org/jboss/forge/grammar/java/MockClass.java b/tests/src/test/resources/org/jboss/forge/grammar/java/MockClass.java index c224cdba..18ab7c22 100644 --- a/tests/src/test/resources/org/jboss/forge/grammar/java/MockClass.java +++ b/tests/src/test/resources/org/jboss/forge/grammar/java/MockClass.java @@ -15,4 +15,12 @@ public class MockClass { public String valueOf(URL url) { return url.getPath(); } + + static { + System.out.println("Hello world!"); + } + + { + System.out.println("Hello world!"); + } } diff --git a/tests/src/test/resources/org/jboss/forge/grammar/java/MockEnum.java b/tests/src/test/resources/org/jboss/forge/grammar/java/MockEnum.java index 33092122..fb92ffdf 100644 --- a/tests/src/test/resources/org/jboss/forge/grammar/java/MockEnum.java +++ b/tests/src/test/resources/org/jboss/forge/grammar/java/MockEnum.java @@ -23,4 +23,12 @@ String getName() { return name(); } + + static { + System.out.println("Hello world!"); + } + + { + System.out.println("Hello world!"); + } }