From f8e9a1acb1fe7212d693c634681a5db218092784 Mon Sep 17 00:00:00 2001 From: Nico Piel Date: Sat, 3 Jan 2026 14:54:52 +0100 Subject: [PATCH 1/4] Adds OpenAPI oneOf for connector properties Adds an OpenAPI/Swagger Schema annotation to the connector properties field to declare concrete property subclasses via oneOf. This enables correct polymorphic schema generation for connector properties, improving API documentation and client code generation. Also imports the Schema annotation required for the new metadata. Signed-off-by: Nico Piel --- .../com/mirth/connect/model/Connector.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/server/src/com/mirth/connect/model/Connector.java b/server/src/com/mirth/connect/model/Connector.java index 070d548bea..40af10baf6 100644 --- a/server/src/com/mirth/connect/model/Connector.java +++ b/server/src/com/mirth/connect/model/Connector.java @@ -24,6 +24,8 @@ import com.mirth.connect.donkey.util.purge.PurgeUtil; import com.thoughtworks.xstream.annotations.XStreamAlias; +import io.swagger.v3.oas.annotations.media.Schema; + /** * A Connector represents a connection to either a source or destination. Each Connector has an * associated Filter and Transformer. A connector is also of a specific Transport type (TCP, HTTP, @@ -40,7 +42,31 @@ public enum Mode { private Integer metaDataId; private String name; + + @Schema(oneOf = { + com.mirth.connect.connectors.dimse.DICOMDispatcherProperties.class, + com.mirth.connect.connectors.dimse.DICOMReceiverProperties.class, + com.mirth.connect.connectors.doc.DocumentDispatcherProperties.class, + com.mirth.connect.connectors.file.FileDispatcherProperties.class, + com.mirth.connect.connectors.file.FileReceiverProperties.class, + com.mirth.connect.connectors.http.HttpDispatcherProperties.class, + com.mirth.connect.connectors.http.HttpReceiverProperties.class, + com.mirth.connect.connectors.jdbc.DatabaseDispatcherProperties.class, + com.mirth.connect.connectors.jdbc.DatabaseReceiverProperties.class, + com.mirth.connect.connectors.jms.JmsDispatcherProperties.class, + com.mirth.connect.connectors.jms.JmsReceiverProperties.class, + com.mirth.connect.connectors.js.JavaScriptDispatcherProperties.class, + com.mirth.connect.connectors.js.JavaScriptReceiverProperties.class, + com.mirth.connect.connectors.smtp.SmtpDispatcherProperties.class, + com.mirth.connect.connectors.tcp.TcpDispatcherProperties.class, + com.mirth.connect.connectors.tcp.TcpReceiverProperties.class, + com.mirth.connect.connectors.vm.VmDispatcherProperties.class, + com.mirth.connect.connectors.vm.VmReceiverProperties.class, + com.mirth.connect.connectors.ws.WebServiceDispatcherProperties.class, + com.mirth.connect.connectors.ws.WebServiceReceiverProperties.class + }) private ConnectorProperties properties; + private Transformer transformer; private Transformer responseTransformer; private Filter filter; From ec4d9c582e9b77081205ed1d05b5f7116dfea39e Mon Sep 17 00:00:00 2001 From: Nico Piel Date: Sat, 3 Jan 2026 23:36:34 +0100 Subject: [PATCH 2/4] Adds dynamic OpenAPI schemas for connector properties Replaces a hardcoded list of connector property types with runtime discovery to generate the OpenAPI schema for connector properties. Uses reflection to find concrete ConnectorProperties subclasses and ModelConverters to register their schemas, composing a ConnectorProperties oneOf schema in the OpenAPI components. This keeps API docs in sync with available property implementations and removes the need to manually maintain annotation lists. It also ignores interfaces and abstract classes and preserves a stable ordering for generated schemas. Signed-off-by: Nico Piel --- .../com/mirth/connect/model/Connector.java | 23 ----- .../server/servlets/SwaggerServlet.java | 88 +++++++++++++++++++ 2 files changed, 88 insertions(+), 23 deletions(-) diff --git a/server/src/com/mirth/connect/model/Connector.java b/server/src/com/mirth/connect/model/Connector.java index 40af10baf6..b74a18f9b9 100644 --- a/server/src/com/mirth/connect/model/Connector.java +++ b/server/src/com/mirth/connect/model/Connector.java @@ -42,29 +42,6 @@ public enum Mode { private Integer metaDataId; private String name; - - @Schema(oneOf = { - com.mirth.connect.connectors.dimse.DICOMDispatcherProperties.class, - com.mirth.connect.connectors.dimse.DICOMReceiverProperties.class, - com.mirth.connect.connectors.doc.DocumentDispatcherProperties.class, - com.mirth.connect.connectors.file.FileDispatcherProperties.class, - com.mirth.connect.connectors.file.FileReceiverProperties.class, - com.mirth.connect.connectors.http.HttpDispatcherProperties.class, - com.mirth.connect.connectors.http.HttpReceiverProperties.class, - com.mirth.connect.connectors.jdbc.DatabaseDispatcherProperties.class, - com.mirth.connect.connectors.jdbc.DatabaseReceiverProperties.class, - com.mirth.connect.connectors.jms.JmsDispatcherProperties.class, - com.mirth.connect.connectors.jms.JmsReceiverProperties.class, - com.mirth.connect.connectors.js.JavaScriptDispatcherProperties.class, - com.mirth.connect.connectors.js.JavaScriptReceiverProperties.class, - com.mirth.connect.connectors.smtp.SmtpDispatcherProperties.class, - com.mirth.connect.connectors.tcp.TcpDispatcherProperties.class, - com.mirth.connect.connectors.tcp.TcpReceiverProperties.class, - com.mirth.connect.connectors.vm.VmDispatcherProperties.class, - com.mirth.connect.connectors.vm.VmReceiverProperties.class, - com.mirth.connect.connectors.ws.WebServiceDispatcherProperties.class, - com.mirth.connect.connectors.ws.WebServiceReceiverProperties.class - }) private ConnectorProperties properties; private Transformer transformer; diff --git a/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java b/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java index 5ac2d11866..dff8737e89 100644 --- a/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java +++ b/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java @@ -10,16 +10,25 @@ package com.mirth.connect.server.servlets; import com.mirth.connect.client.core.BrandingConstants; + +import io.swagger.v3.core.converter.ModelConverters; import io.swagger.v3.jaxrs2.integration.ServletOpenApiContextBuilder; import io.swagger.v3.oas.integration.OpenApiConfigurationException; import io.swagger.v3.oas.integration.SwaggerConfiguration; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.servers.Server; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.stream.Collectors; import javax.servlet.ServletConfig; @@ -28,8 +37,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; +import org.reflections.util.ConfigurationBuilder; import com.mirth.connect.client.core.Version; +import com.mirth.connect.donkey.model.channel.ConnectorProperties; public class SwaggerServlet extends HttpServlet { @@ -66,6 +79,7 @@ public void init(ServletConfig config) throws ServletException { .version(apiVersion.toString()); oas.info(info); + addConnectorPropertiesSchemas(oas); SwaggerConfiguration oasConfig = new SwaggerConfiguration() .openAPI(oas) .resourceClasses(resourceClasses.stream().map(Class::getName).collect(Collectors.toSet())); @@ -81,4 +95,78 @@ public void init(ServletConfig config) throws ServletException { throw new ServletException(e.getMessage(), e); } } + + private void addConnectorPropertiesSchemas(OpenAPI openApi) { + Components components = openApi.getComponents(); + if (components == null) { + components = new Components(); + openApi.setComponents(components); + } + + Map schemas = components.getSchemas(); + if (schemas == null) { + schemas = new java.util.LinkedHashMap<>(); + components.setSchemas(schemas); + } + + SortedSet> subtypes = findConnectorPropertiesSubtypes(); + if (subtypes.isEmpty()) { + return; + } + + ComposedSchema connectorPropertiesSchema = new ComposedSchema(); + Schema existingSchema = schemas.get("ConnectorProperties"); + if (existingSchema instanceof ComposedSchema) { + connectorPropertiesSchema = (ComposedSchema) existingSchema; + } + connectorPropertiesSchema.setOneOf(new ArrayList<>()); + + for (Class subtype : subtypes) { + addSubtypeSchema(schemas, connectorPropertiesSchema, subtype); + } + + schemas.put("ConnectorProperties", connectorPropertiesSchema); + } + + private SortedSet> findConnectorPropertiesSubtypes() { + Reflections reflections = new Reflections(new ConfigurationBuilder() + .forPackages("com.mirth.connect") + .addScanners(new SubTypesScanner(false))); + + SortedSet> subtypes = new TreeSet<>( + Comparator.comparing(Class::getName)); + for (Class subtype : reflections.getSubTypesOf(ConnectorProperties.class)) { + if (!subtype.isInterface() && !java.lang.reflect.Modifier.isAbstract(subtype.getModifiers())) { + subtypes.add(subtype); + } + } + return subtypes; + } + + private void addSubtypeSchema(Map schemas, ComposedSchema connectorPropertiesSchema, Class subtype) { + Map subtypeSchemas = ModelConverters.getInstance().readAll(subtype); + if (subtypeSchemas != null) { + subtypeSchemas.forEach(schemas::putIfAbsent); + } + + String schemaName = resolveSchemaName(subtypeSchemas, subtype); + if (schemaName != null) { + Schema refSchema = new Schema<>(); + refSchema.set$ref("#/components/schemas/" + schemaName); + connectorPropertiesSchema.addOneOfItem(refSchema); + } + } + + private String resolveSchemaName(Map subtypeSchemas, Class subtype) { + if (subtypeSchemas == null || subtypeSchemas.isEmpty()) { + return null; + } + + String simpleName = subtype.getSimpleName(); + if (subtypeSchemas.containsKey(simpleName)) { + return simpleName; + } + + return subtypeSchemas.keySet().iterator().next(); + } } \ No newline at end of file From d775848ad4558f250b3f973d696e4069338f578d Mon Sep 17 00:00:00 2001 From: Nico Piel Date: Tue, 6 Jan 2026 09:48:41 +0100 Subject: [PATCH 3/4] Removes unused Swagger import and cleans whitespace Removes an unused Swagger Schema import and tidies up extraneous blank lines in the Connector class. Cleans up imports/formatting to prepare for property annotation changes on the properties-annotations branch. Signed-off-by: Nico Piel --- server/src/com/mirth/connect/model/Connector.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/server/src/com/mirth/connect/model/Connector.java b/server/src/com/mirth/connect/model/Connector.java index b74a18f9b9..070d548bea 100644 --- a/server/src/com/mirth/connect/model/Connector.java +++ b/server/src/com/mirth/connect/model/Connector.java @@ -24,8 +24,6 @@ import com.mirth.connect.donkey.util.purge.PurgeUtil; import com.thoughtworks.xstream.annotations.XStreamAlias; -import io.swagger.v3.oas.annotations.media.Schema; - /** * A Connector represents a connection to either a source or destination. Each Connector has an * associated Filter and Transformer. A connector is also of a specific Transport type (TCP, HTTP, @@ -43,7 +41,6 @@ public enum Mode { private Integer metaDataId; private String name; private ConnectorProperties properties; - private Transformer transformer; private Transformer responseTransformer; private Filter filter; From d48500fbee771f880bdfe28a73c2aa841ffd9e18 Mon Sep 17 00:00:00 2001 From: Nico Piel Date: Tue, 6 Jan 2026 10:00:11 +0100 Subject: [PATCH 4/4] Use ClasspathHelper for Reflections scanning Replace package-limited scanning with ClasspathHelper-provided URLs for the Reflections configuration to make discovery of ConnectorProperties subtypes more robust across classloaders and deployment layouts. Signed-off-by: Nico Piel --- .../src/com/mirth/connect/server/servlets/SwaggerServlet.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java b/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java index dff8737e89..0b51ff26dd 100644 --- a/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java +++ b/server/src/com/mirth/connect/server/servlets/SwaggerServlet.java @@ -39,6 +39,7 @@ import org.apache.logging.log4j.Logger; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; +import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import com.mirth.connect.client.core.Version; @@ -130,7 +131,7 @@ private void addConnectorPropertiesSchemas(OpenAPI openApi) { private SortedSet> findConnectorPropertiesSubtypes() { Reflections reflections = new Reflections(new ConfigurationBuilder() - .forPackages("com.mirth.connect") + .addUrls(ClasspathHelper.forClassLoader()) .addScanners(new SubTypesScanner(false))); SortedSet> subtypes = new TreeSet<>(