From 0459911a5d2455b2b3b7d7287d2de8a8a88a48d5 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Thu, 6 Nov 2025 18:04:38 -0300 Subject: [PATCH 1/2] OfflineEventReplicator in Spring Boot The mechanism of interpreting the .services of the external REST services was not working for the spring boot case. In particular this causes the OfflineEventReplicator service to not work Issue: 206569 --- .../java/com/genexus/springboot/GXConfig.java | 21 +++++++++++++++++++ .../genexus/springboot/GXImportSelector.java | 10 ++++++--- .../springboot/JaxrsResourcesHolder.java | 19 +++++++++++++++++ .../java/com/genexus/webpanels/WebUtils.java | 2 +- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 gxspringboot/src/main/java/com/genexus/springboot/JaxrsResourcesHolder.java diff --git a/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java b/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java index 912a1bc28..3a75e280e 100644 --- a/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java +++ b/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java @@ -6,8 +6,13 @@ import com.genexus.diagnostics.core.LogManager; import com.genexus.servlet.CorsFilter; import com.genexus.xml.GXXMLSerializable; + import jakarta.annotation.PreDestroy; +import jakarta.servlet.Servlet; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.servlet.ServletContainer; import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -19,6 +24,8 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter; +import java.util.Set; + @Configuration @EnableWebMvc public class GXConfig implements WebMvcConfigurer { @@ -82,6 +89,20 @@ public FilterRegistrationBean urlRewriteFilter() { return registrationBean; } + @Bean + public ServletRegistrationBean jerseyServletRegistration() { + ResourceConfig rc = new ResourceConfig(); + Set> rrcs = JaxrsResourcesHolder.getAll(); + if (!rrcs.isEmpty()) { + rc.registerClasses(rrcs.toArray(new Class[0])); + } + ServletContainer container = new ServletContainer(rc); + ServletRegistrationBean bean = new ServletRegistrationBean<>(container, "/rest/*"); + bean.setName("jersey-servlet"); + bean.setLoadOnStartup(1); + return bean; + } + @PreDestroy public void onDestroy() { GXXMLSerializable.classesCacheMethods.clear(); diff --git a/gxspringboot/src/main/java/com/genexus/springboot/GXImportSelector.java b/gxspringboot/src/main/java/com/genexus/springboot/GXImportSelector.java index db7a7f7c6..7d83e4de6 100644 --- a/gxspringboot/src/main/java/com/genexus/springboot/GXImportSelector.java +++ b/gxspringboot/src/main/java/com/genexus/springboot/GXImportSelector.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.io.ClassPathResource; @@ -20,26 +22,28 @@ public class GXImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { ArrayList restImports = new ArrayList<>(); + Set> rrcs = new HashSet>(); try { Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:*.services"); for (Resource resource : resources) { - selectImport(restImports, resource.getFilename()); + selectImport(rrcs, restImports, resource.getFilename()); } } catch (IOException e){ logger.error("Error loading External Services classes ", e); } + JaxrsResourcesHolder.setAll(rrcs); addWebSocketsImport(restImports); return restImports.toArray(new String[0]); } - private void selectImport(ArrayList restImports, String servicesClassesFileName) { + private void selectImport(Set> rrcs, ArrayList restImports, String servicesClassesFileName) { try { InputStream is = new ClassPathResource(servicesClassesFileName).getInputStream(); if (is != null) { - WebUtils.AddExternalServicesFile(null, restImports, is); + WebUtils.AddExternalServicesFile(rrcs, restImports, is); is.close(); } diff --git a/gxspringboot/src/main/java/com/genexus/springboot/JaxrsResourcesHolder.java b/gxspringboot/src/main/java/com/genexus/springboot/JaxrsResourcesHolder.java new file mode 100644 index 000000000..fe6e139c7 --- /dev/null +++ b/gxspringboot/src/main/java/com/genexus/springboot/JaxrsResourcesHolder.java @@ -0,0 +1,19 @@ +package com.genexus.springboot; + +import java.util.LinkedHashSet; +import java.util.Set; + +public final class JaxrsResourcesHolder { + private static final Set> RESOURCES = new LinkedHashSet<>(); + private JaxrsResourcesHolder() {} + + public static void setAll(Set> rrcs) { + RESOURCES.clear(); + if (rrcs != null) RESOURCES.addAll(rrcs); + } + + public static Set> getAll() { + return new LinkedHashSet<>(RESOURCES); + } +} + diff --git a/java/src/main/java/com/genexus/webpanels/WebUtils.java b/java/src/main/java/com/genexus/webpanels/WebUtils.java index 04b332bc0..99c491c3e 100644 --- a/java/src/main/java/com/genexus/webpanels/WebUtils.java +++ b/java/src/main/java/com/genexus/webpanels/WebUtils.java @@ -523,7 +523,7 @@ public static void AddExternalServicesFile(Set> rrcs, ArrayList if (serviceClass != null) if (rrcs != null) rrcs.add(serviceClass); - else + if (restImports != null) restImports.add(serviceClass.getName()); } reader.close(); From 1db839053d0776d9d7b14a2304ec3787975d6ea2 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Fri, 7 Nov 2025 15:05:08 -0300 Subject: [PATCH 2/2] OfflineEventReplicator in Spring Boot The mechanism of interpreting the .services of the external REST services was not working for the spring boot case. In particular this causes the OfflineEventReplicator service to not work Issue: 206569 --- .../java/com/genexus/springboot/GXConfig.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java b/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java index 3a75e280e..65d9a3312 100644 --- a/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java +++ b/gxspringboot/src/main/java/com/genexus/springboot/GXConfig.java @@ -8,14 +8,14 @@ import com.genexus.xml.GXXMLSerializable; import jakarta.annotation.PreDestroy; -import jakarta.servlet.Servlet; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; +import org.glassfish.jersey.servlet.ServletProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; import org.springframework.core.io.ClassPathResource; import org.springframework.util.AntPathMatcher; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -24,6 +24,8 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter; +import java.util.HashMap; +import java.util.Map; import java.util.Set; @Configuration @@ -90,17 +92,26 @@ public FilterRegistrationBean urlRewriteFilter() { } @Bean - public ServletRegistrationBean jerseyServletRegistration() { + public FilterRegistrationBean jerseyFilter() { ResourceConfig rc = new ResourceConfig(); Set> rrcs = JaxrsResourcesHolder.getAll(); if (!rrcs.isEmpty()) { rc.registerClasses(rrcs.toArray(new Class[0])); + rc.property(ServletProperties.FILTER_FORWARD_ON_404, true); } + ServletContainer container = new ServletContainer(rc); - ServletRegistrationBean bean = new ServletRegistrationBean<>(container, "/rest/*"); - bean.setName("jersey-servlet"); - bean.setLoadOnStartup(1); - return bean; + + FilterRegistrationBean reg = new FilterRegistrationBean<>(container); + reg.addUrlPatterns("/rest/*"); + reg.setName("jersey-filter"); + reg.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); + + Map initParams = new HashMap<>(); + initParams.put(ServletProperties.FILTER_CONTEXT_PATH, "/rest"); + reg.setInitParameters(initParams); + + return reg; } @PreDestroy