This is an automated email from the ASF dual-hosted git repository. tallison pushed a commit to branch TIKA-4613 in repository https://gitbox.apache.org/repos/asf/tika.git
commit 54283f483e04c8dd2f09a1b77dfe17f3ea0d492e Author: tallison <[email protected]> AuthorDate: Tue Jan 6 15:41:44 2026 -0500 TIKA-4613 -- look for jsonconfig constructor, fall back to no-arg --- .../org/apache/tika/serialization/TikaModule.java | 13 ++++--------- .../tika/metadata/filter/TestMetadataFilter.java | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tika-serialization/src/main/java/org/apache/tika/serialization/TikaModule.java b/tika-serialization/src/main/java/org/apache/tika/serialization/TikaModule.java index 249f7f71cf..181e6b90e1 100644 --- a/tika-serialization/src/main/java/org/apache/tika/serialization/TikaModule.java +++ b/tika-serialization/src/main/java/org/apache/tika/serialization/TikaModule.java @@ -227,12 +227,9 @@ public class TikaModule extends SimpleModule { */ private static class TikaComponentDeserializer extends JsonDeserializer<Object> { private final Class<?> expectedType; - // Plain mapper for property updates (avoids infinite recursion with registered types) - private final ObjectMapper plainMapper; TikaComponentDeserializer(Class<?> expectedType) { this.expectedType = expectedType; - this.plainMapper = new ObjectMapper(); } @Override @@ -307,19 +304,17 @@ public class TikaModule extends SimpleModule { } else if (cleanedConfig == null || cleanedConfig.isEmpty()) { // If no config, use default constructor instance = clazz.getDeclaredConstructor().newInstance(); - } else if (SelfConfiguring.class.isAssignableFrom(clazz)) { - // SelfConfiguring components: prefer JsonConfig constructor if available + } else { + // Try JsonConfig constructor first (works for any component) Constructor<?> jsonConfigCtor = findJsonConfigConstructor(clazz); if (jsonConfigCtor != null) { String json = mapper.writeValueAsString(cleanedConfig); instance = jsonConfigCtor.newInstance((JsonConfig) () -> json); } else { + // Fall back to no-arg constructor + Jackson bean deserialization instance = clazz.getDeclaredConstructor().newInstance(); + mapper.readerForUpdating(instance).readValue(cleanedConfig); } - } else { - // Non-SelfConfiguring: use Jackson bean deserialization - instance = clazz.getDeclaredConstructor().newInstance(); - plainMapper.readerForUpdating(instance).readValue(cleanedConfig); } // Call initialize() on Initializable components diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/filter/TestMetadataFilter.java b/tika-serialization/src/test/java/org/apache/tika/metadata/filter/TestMetadataFilter.java index 197a116702..04363eeec3 100644 --- a/tika-serialization/src/test/java/org/apache/tika/metadata/filter/TestMetadataFilter.java +++ b/tika-serialization/src/test/java/org/apache/tika/metadata/filter/TestMetadataFilter.java @@ -283,6 +283,25 @@ public class TestMetadataFilter extends TikaTest { assertEquals(2, metadata.names().length); } + /** + * Test that TikaModule correctly instantiates components that only have a JsonConfig + * constructor (no no-arg constructor). This verifies the fix for TIKA-4582. + */ + @Test + public void testJsonConfigOnlyFilter() throws Exception { + TikaLoader loader = TikaLoader.load(getConfigPath(getClass(), "TIKA-4582-json-config-only.json")); + Metadata metadata = new Metadata(); + metadata.set("title", "my title"); + metadata.set("author", "my author"); + + MetadataFilter filter = loader.get(MetadataFilter.class); + metadata = filterOne(filter, metadata); + + assertEquals(2, metadata.size()); + assertEquals("TEST_my title", metadata.get("title")); + assertEquals("TEST_my author", metadata.get("author")); + } + private static Metadata filterOne(MetadataFilter filter, Metadata singleMetadata) throws TikaException { List<Metadata> list = new ArrayList<>(); list.add(singleMetadata);
