diff --git a/core-java-modules/core-java-19/pom.xml b/core-java-modules/core-java-19/pom.xml
new file mode 100644
index 0000000000..096b13e679
--- /dev/null
+++ b/core-java-modules/core-java-19/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ com.baeldung.core-java-modules
+ core-java-modules
+ 0.0.1-SNAPSHOT
+
+
+ core-java-19
+
+
+ 19
+ 19
+ UTF-8
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 19
+ 19
+ --enable-preview
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java
new file mode 100644
index 0000000000..961575c88d
--- /dev/null
+++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/GPSPoint.java
@@ -0,0 +1,3 @@
+package com.baeldung.features.records;
+
+public record GPSPoint (double lat, double lng) { }
\ No newline at end of file
diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java
new file mode 100644
index 0000000000..00851c8d5e
--- /dev/null
+++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/ILocation.java
@@ -0,0 +1,9 @@
+package com.baeldung.features.records;
+
+public sealed interface ILocation permits Location {
+ default String getName() {
+ return switch (this) {
+ case Location(var name, var ignored) -> name;
+ };
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java
new file mode 100644
index 0000000000..fb50fbe645
--- /dev/null
+++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/Location.java
@@ -0,0 +1,5 @@
+package com.baeldung.features.records;
+
+public record Location(String name, GPSPoint gpsPoint) implements ILocation {
+}
+
diff --git a/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java
new file mode 100644
index 0000000000..e7ddfef5f0
--- /dev/null
+++ b/core-java-modules/core-java-19/src/main/java/com/baeldung/features/records/LocationWrapper.java
@@ -0,0 +1,3 @@
+package com.baeldung.features.records;
+
+public record LocationWrapper(T t, String description) { }
diff --git a/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java
new file mode 100644
index 0000000000..10ad33b411
--- /dev/null
+++ b/core-java-modules/core-java-19/src/test/java/com/baeldung/features/JEP405RecordPatternsUnitTest.java
@@ -0,0 +1,99 @@
+package com.baeldung.features;
+
+import com.baeldung.features.records.GPSPoint;
+import com.baeldung.features.records.Location;
+import com.baeldung.features.records.LocationWrapper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+
+public class JEP405RecordPatternsUnitTest {
+
+ Object object = new Location("Home", new GPSPoint(1.0, 2.0));
+
+ @Test
+ void givenObject_whenTestInstanceOfAndCastIdiom_shouldMatchNewInstanceOf() {
+ // old Code
+ if (object instanceof Location) {
+ Location l = (Location) object;
+ assertThat(l).isInstanceOf(Location.class);
+ }
+ // new code
+ if (object instanceof Location l) {
+ assertThat(l).isInstanceOf(Location.class);
+ }
+ }
+
+ @Test
+ void givenObject_whenTestDestruct_shouldMatch() {
+ // when
+ if (object instanceof Location(var name, var gpsPoint)) {
+ // then
+ assertThat(name).isEqualTo("Home");
+ assertThat(gpsPoint).isInstanceOf(GPSPoint.class);
+ }
+
+ if (object instanceof Location(var name, GPSPoint(var lat, var lng))) {
+ assertThat(lat).isEqualTo(1.0);
+ assertThat(lng).isEqualTo(2.0);
+ }
+ }
+
+ @Test
+ void givenObjectIsNull_whenTestNullCheck_shouldNotMatch() {
+ Location l = null;
+ if (l instanceof Location location) {
+ assertThat(location).isNotNull();
+ }
+ }
+
+
+ @Test
+ void givenObject_whenTestGenericTypeInstanceOf_shouldMatch() {
+ LocationWrapper locationWrapper = new LocationWrapper<>(new Location("Home", new GPSPoint(1.0, 2.0)), "Description");
+ if (locationWrapper instanceof LocationWrapper(var ignored, var description)) {
+ assertThat(description).isEqualTo("Description");
+ }
+ }
+
+
+ @Test
+ void givenObject_whenTestSwitchExpressionWithTypePattern_shouldMatch() {
+ String result = switch (object) {
+ case Location l -> l.name();
+ default -> "default";
+ };
+ assertThat(result).isEqualTo("Home");
+ Double result2 = switch (object) {
+ case Location(var name, GPSPoint(var lat, var lng)) -> lat;
+ default -> 0.0;
+ };
+ assertThat(result2).isEqualTo(1.0);
+ }
+
+ @Test
+ void givenObject_whenTestGuardedSwitchExpressionWithTypePattern_shouldMatchAndGuard() {
+ String result = switch (object) {
+ case Location(var name, var ignored) when name.equals("Home") -> "Test";
+ case Location(var name, var ignored) -> name;
+ default -> "default";
+ };
+ assertThat(result).isEqualTo("Test");
+
+ String otherResult = switch (new Location("Other", new GPSPoint(1.0, 2.0))) {
+ case Location(var name, var ignored) when name.equals("Home") -> "Test";
+ case Location(var name, var ignored) -> name;
+ default -> "default";
+ };
+ assertThat(otherResult).isEqualTo("Other");
+
+ Object noLocation = new GPSPoint(1.0, 2.0);
+ String noLocationResult = switch (noLocation) {
+ case Location(var name, var ignored) when name.equals("Home") -> "Test";
+ case Location(var name, var ignored) -> name;
+ default -> "default";
+ };
+ assertThat(noLocationResult).isEqualTo("default");
+ }
+}
diff --git a/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java
new file mode 100644
index 0000000000..c329421208
--- /dev/null
+++ b/core-java-modules/core-java-reflection/src/main/java/com/baeldung/getclassfromstr/MyNiceClass.java
@@ -0,0 +1,7 @@
+package com.baeldung.getclassfromstr;
+
+public class MyNiceClass {
+ public String greeting(){
+ return "Hi there, I wish you all the best!";
+ }
+}
diff --git a/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java
new file mode 100644
index 0000000000..f0e8022c02
--- /dev/null
+++ b/core-java-modules/core-java-reflection/src/test/java/com/baeldung/getclassfromstr/GetClassObjectFromStringUnitTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.getclassfromstr;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class GetClassObjectFromStringUnitTest {
+ @Test
+ void givenQualifiedClsName_whenUsingClassForName_shouldGetExpectedClassObject() throws ReflectiveOperationException {
+ Class cls = Class.forName("com.baeldung.getclassfromstr.MyNiceClass");
+ assertNotNull(cls);
+
+ MyNiceClass myNiceObject = (MyNiceClass) cls.getDeclaredConstructor().newInstance();
+ assertNotNull(myNiceObject);
+ assertEquals("Hi there, I wish you all the best!", myNiceObject.greeting());
+ }
+
+ @Test
+ void givenSimpleName_whenUsingClassForName_shouldGetExpectedException() {
+ assertThrows(ClassNotFoundException.class, () -> Class.forName("MyNiceClass"));
+ }
+}
diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml
index f1c5bfe874..cc137d08b6 100644
--- a/core-java-modules/pom.xml
+++ b/core-java-modules/pom.xml
@@ -151,4 +151,4 @@
-
\ No newline at end of file
+
diff --git a/pom.xml b/pom.xml
index 3d2863e1f2..c4c9dbf925 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1130,6 +1130,7 @@
+
core-java-modules/core-java-collections-set
core-java-modules/core-java-collections-list-4
core-java-modules/core-java-collections-maps-4
diff --git a/saas-modules/pom.xml b/saas-modules/pom.xml
index 7a626e7663..7e8adebdd9 100644
--- a/saas-modules/pom.xml
+++ b/saas-modules/pom.xml
@@ -20,6 +20,7 @@
stripe
twilio
twitter4j
+ sentry-servlet
diff --git a/saas-modules/sentry-servlet/pom.xml b/saas-modules/sentry-servlet/pom.xml
new file mode 100644
index 0000000000..c86fcbce03
--- /dev/null
+++ b/saas-modules/sentry-servlet/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ saas-modules
+ 1.0.0-SNAPSHOT
+
+ sentry-servlet
+ sentry-servlet
+ war
+
+
+ 6.11.0
+ 1.10.4
+
+
+
+
+ io.sentry
+ sentry-servlet
+ ${sentry.version}
+
+
+
+ javax.servlet
+ javax.servlet-api
+ provided
+
+
+
+
+
+
+ org.codehaus.cargo
+ cargo-maven3-plugin
+ ${cargo.version}
+
+
+ tomcat9x
+ embedded
+
+
+
+
+
+
\ No newline at end of file
diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java
new file mode 100644
index 0000000000..7a32094221
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/servlet/FaultyServlet.java
@@ -0,0 +1,32 @@
+package com.baeldung.sentry.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet(urlPatterns = "/fault", loadOnStartup = 1)
+public class FaultyServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+ String op = req.getParameter("op");
+ if( "fault".equals(op) ) {
+ resp.sendError(500, "Something bad happened !");
+ }
+ else if ( "exception".equals(op) ) {
+ throw new IllegalArgumentException("Internal error");
+ }
+ else {
+ resp.setStatus(200);
+ resp.setContentType("text/plain");
+ resp.getWriter().println("OK");
+ }
+ }
+}
diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java
new file mode 100644
index 0000000000..6f25dd36aa
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryContextListener.java
@@ -0,0 +1,39 @@
+package com.baeldung.sentry.support;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+import io.sentry.Sentry;
+import io.sentry.SentryLevel;
+
+@WebListener
+public class SentryContextListener implements ServletContextListener {
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+
+ // Besides standard supported locations, let's also allow the DSN to be
+ // passed using servlet container managed parameters. This can be useful if your app
+ // is hosted in a shared application server.
+ ServletContext context = sce.getServletContext();
+ String sentryDsn = context.getInitParameter("sentry.dsn");
+
+ if ( sentryDsn != null ) {
+ context.log("[I21] sentry.dsn init parameter found. Configuring Sentry SDK...");
+ Sentry.init(sentryDsn);
+ }
+ else {
+ context.log("[I25] sentry.dsn init parameter not found. Configuring Sentry SDK with defaults");
+ Sentry.init();
+ }
+
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ sce.getServletContext().log("[I34] shutting down context");
+ Sentry.captureMessage("[I35] contextDestroyed", SentryLevel.INFO);
+ Sentry.close();
+ }
+}
diff --git a/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java
new file mode 100644
index 0000000000..e853368ad9
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/main/java/com/baeldung/sentry/support/SentryFilter.java
@@ -0,0 +1,32 @@
+package com.baeldung.sentry.support;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletResponse;
+
+import io.sentry.Sentry;
+import io.sentry.SentryLevel;
+
+@WebFilter(urlPatterns = "/*")
+public class SentryFilter implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ try {
+ chain.doFilter(request, response);
+ int rc = ((HttpServletResponse) response).getStatus();
+ if (rc/100 == 5) {
+ Sentry.captureMessage("Application error: code=" + rc, SentryLevel.ERROR);
+ }
+ } catch (Throwable t) {
+ Sentry.captureException(t);
+ throw t;
+ }
+ }
+}
diff --git a/saas-modules/sentry-servlet/src/main/resources/sentry.properties b/saas-modules/sentry-servlet/src/main/resources/sentry.properties
new file mode 100644
index 0000000000..c937874420
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/main/resources/sentry.properties
@@ -0,0 +1,3 @@
+# Sentry configuration file
+# put your DSN here
+dsn=https://xxxxxxxxxxxxxxxx@zzzzzzz.ingest.sentry.io/wwww
\ No newline at end of file
diff --git a/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml b/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..e89de5f352
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java b/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java
new file mode 100644
index 0000000000..3db0d1c66e
--- /dev/null
+++ b/saas-modules/sentry-servlet/src/test/java/com/baeldung/sentry/servlet/FaultyServletLiveTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.sentry.servlet;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.junit.jupiter.api.Test;
+
+class FaultyServletLiveTest {
+
+
+ @Test
+ void testGivenFaultyRequestWithNoQueryString_thenSuccess() throws Exception {
+
+ //int port = getServerPort();
+ URL u = new URL("http://localhost:8080/sentry-servlet/fault");
+ HttpURLConnection conn = (HttpURLConnection)u.openConnection();
+ int rc = conn.getResponseCode();
+ assertThat(rc)
+ .isEqualTo(200);
+ }
+
+ @Test
+ void testGivenFaultyRequestWithFaultString_thenFail() throws Exception {
+
+ //int port = getServerPort();
+ URL u = new URL("http://localhost:8080/sentry-servlet/fault?fault=true");
+ HttpURLConnection conn = (HttpURLConnection)u.openConnection();
+ int rc = conn.getResponseCode();
+ assertThat(rc)
+ .isEqualTo(500);
+ }
+
+ @Test
+ void testGivenFaultyRequestWithExceptionString_thenFail() throws Exception {
+
+ //int port = getServerPort();
+ URL u = new URL("http://localhost:8080/sentry-servlet/fault?exception=true");
+ HttpURLConnection conn = (HttpURLConnection)u.openConnection();
+ int rc = conn.getResponseCode();
+ assertThat(rc)
+ .isEqualTo(500);
+ }
+
+}