diff --git a/libraries-4/pom.xml b/libraries-4/pom.xml
index 87e618ee5b..3869570636 100644
--- a/libraries-4/pom.xml
+++ b/libraries-4/pom.xml
@@ -109,9 +109,30 @@
javafx-fxml
${javafx.version}
+
+
+ fr.inria.gforge.spoon
+ spoon-core
+ ${spoon-core.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson-core.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson-annotations.version}
+
+
+ 2.14.2
+ 2.14.2
1.2.6
8.2.0
1.1.0
@@ -129,6 +150,7 @@
2.2.4
1.2.0
19
+ 10.3.0
\ No newline at end of file
diff --git a/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightProcessor.java b/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightProcessor.java
new file mode 100644
index 0000000000..7298cffa12
--- /dev/null
+++ b/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightProcessor.java
@@ -0,0 +1,15 @@
+package com.baeldung.spoon;
+
+import spoon.processing.AbstractProcessor;
+import spoon.reflect.code.CtComment;
+import spoon.reflect.code.CtComment.CommentType;
+import spoon.reflect.declaration.CtClass;
+
+public class AddCopyrightProcessor extends AbstractProcessor> {
+
+ @Override
+ public void process(CtClass> clazz) {
+ CtComment comment = getFactory().createComment("Copyright(c) 2023 etc", CommentType.JAVADOC);
+ clazz.addComment(comment);
+ }
+}
diff --git a/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightTransformer.java b/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightTransformer.java
new file mode 100644
index 0000000000..b7f20b6b85
--- /dev/null
+++ b/libraries-4/src/main/java/com/baeldung/spoon/AddCopyrightTransformer.java
@@ -0,0 +1,31 @@
+package com.baeldung.spoon;
+
+import spoon.Launcher;
+import spoon.SpoonAPI;
+import spoon.reflect.CtModel;
+import spoon.reflect.code.CtComment;
+import spoon.reflect.code.CtComment.CommentType;
+import spoon.reflect.declaration.CtClass;
+
+public class AddCopyrightTransformer {
+
+ public void addCopyright(String source) {
+
+ SpoonAPI spoon = new Launcher();
+ spoon.addInputResource(source);
+ spoon.getEnvironment().setLevel("DEBUG");
+ CtModel model = spoon.buildModel();
+
+ model.filterChildren((el) -> el instanceof CtClass>)
+ .forEach((CtClass> cl) -> {
+ CtComment comment = cl.getFactory()
+ .createComment("Copyright(c) 2023 etc", CommentType.JAVADOC);
+ cl.addComment(comment);
+ });
+
+ spoon.setSourceOutputDirectory("./target");
+ spoon.prettyprint();
+ }
+
+
+}
diff --git a/libraries-4/src/main/java/com/baeldung/spoon/ClassReporter.java b/libraries-4/src/main/java/com/baeldung/spoon/ClassReporter.java
new file mode 100644
index 0000000000..a532b83be1
--- /dev/null
+++ b/libraries-4/src/main/java/com/baeldung/spoon/ClassReporter.java
@@ -0,0 +1,111 @@
+package com.baeldung.spoon;
+
+import spoon.Launcher;
+import spoon.SpoonAPI;
+import spoon.reflect.CtModel;
+import spoon.reflect.declaration.CtClass;
+import spoon.reflect.declaration.CtMethod;
+import spoon.support.sniper.SniperJavaPrettyPrinter;
+
+/**
+ * Loads a given class and creates a summary o
+ */
+public class ClassReporter {
+
+
+ public MethodSummary generateMethodSummaryReport(String source) {
+
+ SpoonAPI spoon = new Launcher();
+ spoon.addInputResource(source);
+ CtModel model = spoon.buildModel();
+ MethodSummary report = new MethodSummary();
+ model.filterChildren((el) -> el instanceof CtClass>)
+ .forEach((CtClass> clazz) -> processMethods(report,clazz));
+
+ return report;
+ }
+
+ private void processMethods(MethodSummary report, CtClass> ctClass) {
+
+ ctClass.filterChildren((c) -> c instanceof CtMethod> )
+ .forEach((CtMethod> m) -> {
+ if (m.isPublic()) {
+ report.addPublicMethod();
+ }
+ else if ( m.isPrivate()) {
+ report.addPrivateMethod();
+ }
+ else if ( m.isProtected()) {
+ report.addProtectedMethod();
+ }
+ else {
+ report.addPackagePrivateMethod();
+ }
+ });
+ }
+
+
+ public static class MethodSummary {
+ private int totalMethodCount;
+ private int publicMethodCount;
+ private int protectedMethodCount;
+ private int packagePrivateMethodCount;
+ private int privateMethodCount;
+
+ void addPublicMethod() {
+ totalMethodCount++;
+ publicMethodCount++;
+ }
+
+ void addPrivateMethod() {
+ totalMethodCount++;
+ privateMethodCount++;
+ }
+
+ void addProtectedMethod() {
+ totalMethodCount++;
+ protectedMethodCount++;
+ }
+
+ void addPackagePrivateMethod() {
+ totalMethodCount++;
+ packagePrivateMethodCount++;
+ }
+
+ /**
+ * @return the totalMethodCount
+ */
+ public int getTotalMethodCount() {
+ return totalMethodCount;
+ }
+
+ /**
+ * @return the publicMethodCount
+ */
+ public int getPublicMethodCount() {
+ return publicMethodCount;
+ }
+
+ /**
+ * @return the protectedMethodCount
+ */
+ public int getProtectedMethodCount() {
+ return protectedMethodCount;
+ }
+
+ /**
+ * @return the privateMethodCount
+ */
+ public int getPrivateMethodCount() {
+ return privateMethodCount;
+ }
+
+ /**
+ * @return the privateMethodCount
+ */
+ public int getPackagePrivateMethodCount() {
+ return packagePrivateMethodCount;
+ }
+
+ }
+}
diff --git a/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightProcessorUnitTest.java b/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightProcessorUnitTest.java
new file mode 100644
index 0000000000..44b45342b0
--- /dev/null
+++ b/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightProcessorUnitTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.spoon;
+
+import org.junit.Test;
+
+import spoon.Launcher;
+import spoon.SpoonAPI;
+
+public class AddCopyrightProcessorUnitTest {
+
+ @Test
+ public void whenAddCopyright_thenSuccess() {
+
+ SpoonAPI spoon = new Launcher();
+ spoon.addProcessor(new AddCopyrightProcessor());
+ spoon.addInputResource("src/test/resources/spoon/SpoonClassToTest.java");
+ spoon.setSourceOutputDirectory("./target/spoon-processed");
+ spoon.buildModel();
+ spoon.process();
+ spoon.prettyprint();
+
+ }
+
+}
diff --git a/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightTransformerUnitTest.java b/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightTransformerUnitTest.java
new file mode 100644
index 0000000000..af6ba9e16b
--- /dev/null
+++ b/libraries-4/src/test/java/com/baeldung/spoon/AddCopyrightTransformerUnitTest.java
@@ -0,0 +1,17 @@
+package com.baeldung.spoon;
+
+import org.junit.Test;
+
+public class AddCopyrightTransformerUnitTest {
+
+
+
+ @Test
+ public void whenAddCopyright_thenSuccess() {
+
+ AddCopyrightTransformer transformer = new AddCopyrightTransformer();
+ transformer.addCopyright("src/test/resources/spoon/SpoonClassToTest.java");
+
+ }
+
+}
diff --git a/libraries-4/src/test/java/com/baeldung/spoon/ClassReporterUnitTest.java b/libraries-4/src/test/java/com/baeldung/spoon/ClassReporterUnitTest.java
new file mode 100644
index 0000000000..38e6d8ddc7
--- /dev/null
+++ b/libraries-4/src/test/java/com/baeldung/spoon/ClassReporterUnitTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.spoon;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+import com.baeldung.spoon.ClassReporter.MethodSummary;
+
+public class ClassReporterUnitTest {
+
+ @Test
+ public void givenBrokenClass_whenGenerateReport_thenSuccess() {
+ ClassReporter reporter = new ClassReporter();
+ MethodSummary report = reporter.generateMethodSummaryReport("src/test/resources/spoon/BrokenClass.java");
+
+ assertThat(report).isNotNull();
+ assertThat(report.getPrivateMethodCount()).isEqualTo(0);
+ assertThat(report.getPublicMethodCount()).isEqualTo(1);
+ assertThat(report.getProtectedMethodCount()).isEqualTo(1);
+
+ }
+
+ @Test
+ public void whenGenerateReport_thenSuccess() {
+
+ ClassReporter reporter = new ClassReporter();
+ MethodSummary report = reporter.generateMethodSummaryReport("src/test/resources/spoon/SpoonClassToTest.java");
+ assertThat(report).isNotNull();
+ assertThat(report.getPackagePrivateMethodCount()).isEqualTo(1);
+ assertThat(report.getPublicMethodCount()).isEqualTo(1);
+ assertThat(report.getPrivateMethodCount()).isEqualTo(1);
+ }
+
+}
diff --git a/libraries-4/src/test/resources/spoon/BrokenClass.java b/libraries-4/src/test/resources/spoon/BrokenClass.java
new file mode 100644
index 0000000000..cf603b2afb
--- /dev/null
+++ b/libraries-4/src/test/resources/spoon/BrokenClass.java
@@ -0,0 +1,12 @@
+package spoon;
+public class BrokenClass {
+
+ // Syntax error
+ pluvic void brokenMethod() {}
+
+ // Syntax error
+ protected void protectedMethod() thraws Exception {}
+
+ // Public method
+ public void publicMethod() {}
+}
\ No newline at end of file
diff --git a/libraries-4/src/test/resources/spoon/SpoonClassToTest.java b/libraries-4/src/test/resources/spoon/SpoonClassToTest.java
new file mode 100644
index 0000000000..75f06885c0
--- /dev/null
+++ b/libraries-4/src/test/resources/spoon/SpoonClassToTest.java
@@ -0,0 +1,28 @@
+package spoon;
+
+import some.superduper.HelperClass;
+import some.superduper.SomeVO;
+
+public class SpoonClassToTest {
+
+ private static HelperClass helper;
+
+ public SpoonClassToTest() {}
+
+ public int publicMethod() {}
+
+ private int internalStuff() {}
+
+ protected SomeVO protectedMethod() {
+ return new SomeVO();
+ }
+
+ void packageProtectedMethod() {
+
+ try {
+ HelperClass.callSomeMethodThatThrows();
+ }
+ catch(Exception ignored) {}
+ }
+
+}
\ No newline at end of file
diff --git a/messaging-modules/rabbitmq/README.md b/messaging-modules/rabbitmq/README.md
index 93bb795d7b..8cfcca3378 100644
--- a/messaging-modules/rabbitmq/README.md
+++ b/messaging-modules/rabbitmq/README.md
@@ -9,3 +9,4 @@ This module contains articles about RabbitMQ.
- [Channels and Connections in RabbitMQ](https://www.baeldung.com/java-rabbitmq-channels-connections)
- [Create Dynamic Queues in RabbitMQ](https://www.baeldung.com/rabbitmq-dynamic-queues)
+