This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch TIKA-4585-simplify-serialization
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to 
refs/heads/TIKA-4585-simplify-serialization by this push:
     new 77a7e42c8 TIKA-4585 -- rm unused mixins
77a7e42c8 is described below

commit 77a7e42c8ff11bbd4c5142785fd456fdce2e4569
Author: tallison <[email protected]>
AuthorDate: Sat Dec 20 23:48:47 2025 -0500

    TIKA-4585 -- rm unused mixins
---
 .../tika/serialization/TikaAbstractTypeMixins.java | 313 ---------------------
 1 file changed, 313 deletions(-)

diff --git 
a/tika-serialization/src/main/java/org/apache/tika/serialization/TikaAbstractTypeMixins.java
 
b/tika-serialization/src/main/java/org/apache/tika/serialization/TikaAbstractTypeMixins.java
deleted file mode 100644
index 2a11b0e76..000000000
--- 
a/tika-serialization/src/main/java/org/apache/tika/serialization/TikaAbstractTypeMixins.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tika.serialization;
-
-import java.io.IOException;
-import java.lang.reflect.Modifier;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.BeanDescription;
-import com.fasterxml.jackson.databind.DeserializationConfig;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationConfig;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.tika.config.loader.ComponentInstantiator;
-import org.apache.tika.exception.TikaConfigException;
-
-/**
- * Jackson module that handles deserialization of abstract types using wrapper 
object format.
- * <p>
- * Automatically applies to ANY abstract type (interface or abstract class) 
without
- * requiring hardcoded type lists. Supports both formats:
- * <ul>
- *   <li>Wrapper format: {@code {"type-name": {"prop": "value"}}}</li>
- *   <li>Legacy @class format: {@code {"@class": "fqcn", "prop": "value"}}</li>
- * </ul>
- * <p>
- * Example:
- * <pre>
- * "digesterFactory": {
- *   "commons-digester-factory": {
- *     "markLimit": 100000
- *   }
- * }
- * </pre>
- */
-public final class TikaAbstractTypeMixins {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(TikaAbstractTypeMixins.class);
-
-    private TikaAbstractTypeMixins() {
-        // Utility class
-    }
-
-    /**
-     * Registers the abstract type handling module on the given ObjectMapper.
-     * This includes both serializers (to add type wrappers) and deserializers
-     * (to resolve type wrappers).
-     *
-     * @param mapper the ObjectMapper to configure
-     */
-    public static void registerDeserializers(ObjectMapper mapper) {
-        SimpleModule module = new SimpleModule("TikaAbstractTypes");
-        module.setDeserializerModifier(new 
AbstractTypeDeserializerModifier(mapper));
-        module.setSerializerModifier(new 
AbstractTypeSerializerModifier(mapper));
-        mapper.registerModule(module);
-    }
-
-    /**
-     * Modifier that intercepts deserialization of abstract types and applies
-     * wrapper object handling.
-     */
-    private static class AbstractTypeDeserializerModifier extends 
BeanDeserializerModifier {
-
-        private final ObjectMapper mapper;
-
-        AbstractTypeDeserializerModifier(ObjectMapper mapper) {
-            this.mapper = mapper;
-        }
-
-        @Override
-        public JsonDeserializer<?> modifyDeserializer(DeserializationConfig 
config,
-                                                       BeanDescription 
beanDesc,
-                                                       JsonDeserializer<?> 
deserializer) {
-            Class<?> beanClass = beanDesc.getBeanClass();
-
-            // Skip types that shouldn't use wrapper format
-            if (shouldSkip(beanClass)) {
-                return deserializer;
-            }
-
-            // Only handle abstract types (interfaces or abstract classes)
-            if (beanClass.isInterface() || 
Modifier.isAbstract(beanClass.getModifiers())) {
-                LOG.debug("Registering wrapper deserializer for abstract type: 
{}",
-                        beanClass.getName());
-                return new WrapperObjectDeserializer<>(beanClass, mapper);
-            }
-
-            return deserializer;
-        }
-
-        private boolean shouldSkip(Class<?> beanClass) {
-            // Skip primitives and their wrappers
-            if (beanClass.isPrimitive()) {
-                return true;
-            }
-
-            // Skip common JDK types
-            String name = beanClass.getName();
-            if (name.startsWith("java.") || name.startsWith("javax.")) {
-                return true;
-            }
-
-            // Skip arrays
-            if (beanClass.isArray()) {
-                return true;
-            }
-
-            return false;
-        }
-    }
-
-    /**
-     * Deserializer that handles wrapper object format for abstract types.
-     */
-    private static class WrapperObjectDeserializer<T> extends 
JsonDeserializer<T> {
-
-        private final Class<?> abstractType;
-        private final ObjectMapper mapper;
-
-        WrapperObjectDeserializer(Class<?> abstractType, ObjectMapper mapper) {
-            this.abstractType = abstractType;
-            this.mapper = mapper;
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public T deserialize(JsonParser p, DeserializationContext ctxt) throws 
IOException {
-            JsonNode node = p.readValueAsTree();
-
-            if (!node.isObject() || node.isEmpty()) {
-                // Let Jackson's default handling fail appropriately
-                return (T) ctxt.handleUnexpectedToken(abstractType, p);
-            }
-
-            // Check for legacy "@class" format
-            if (node.has("@class")) {
-                String typeName = node.get("@class").asText();
-                // Create config node without @class
-                com.fasterxml.jackson.databind.node.ObjectNode configObj =
-                        mapper.createObjectNode();
-                node.properties().forEach(entry -> {
-                    if (!"@class".equals(entry.getKey())) {
-                        configObj.set(entry.getKey(), entry.getValue());
-                    }
-                });
-                return instantiateType(typeName, configObj, ctxt);
-            }
-
-            // Check for wrapper format: single field whose value is an object
-            // e.g., {"commons-digester-factory": {"markLimit": 100000}}
-            if (node.size() == 1) {
-                String typeName = node.fieldNames().next();
-                JsonNode configNode = node.get(typeName);
-                // Only treat as wrapper if the value is an object (not 
primitive/array)
-                if (configNode.isObject()) {
-                    return instantiateType(typeName, configNode, ctxt);
-                }
-            }
-
-            // Not wrapper format - this is likely an error (can't instantiate 
abstract type)
-            // Throw JsonMappingException so ConfigLoader wraps it in 
TikaConfigException
-            throw JsonMappingException.from(p,
-                    "Cannot deserialize abstract type " + 
abstractType.getSimpleName() +
-                    ". Use wrapper format: {\"concrete-type-name\": {...}} or 
" +
-                    "legacy format: {\"@class\": 
\"fully.qualified.ClassName\", ...}");
-        }
-
-        private T instantiateType(String typeName, JsonNode configNode,
-                                   DeserializationContext ctxt) throws 
IOException {
-            try {
-                Class<?> concreteClass = 
ComponentNameResolver.resolveClass(typeName,
-                        TikaAbstractTypeMixins.class.getClassLoader());
-                return ComponentInstantiator.instantiate(concreteClass, 
configNode, mapper);
-            } catch (ClassNotFoundException e) {
-                throw JsonMappingException.from(ctxt.getParser(),
-                        "Unknown type '" + typeName + "' for " + 
abstractType.getSimpleName());
-            } catch (TikaConfigException e) {
-                throw JsonMappingException.from(ctxt.getParser(),
-                        "Failed to instantiate " + typeName + ": " + 
e.getMessage());
-            }
-        }
-    }
-
-    /**
-     * Modifier that intercepts serialization of values declared as abstract 
types
-     * and wraps them with type information.
-     */
-    private static class AbstractTypeSerializerModifier extends 
BeanSerializerModifier {
-
-        private final ObjectMapper mapper;
-
-        AbstractTypeSerializerModifier(ObjectMapper mapper) {
-            this.mapper = mapper;
-        }
-
-        @Override
-        public JsonSerializer<?> modifySerializer(SerializationConfig config,
-                                                   BeanDescription beanDesc,
-                                                   JsonSerializer<?> 
serializer) {
-            Class<?> beanClass = beanDesc.getBeanClass();
-
-            // Skip types that shouldn't use wrapper format
-            if (shouldSkip(beanClass)) {
-                return serializer;
-            }
-
-            // For concrete Tika types, wrap with type name if they 
extend/implement an abstract type
-            // This ensures polymorphic types in lists get properly wrapped
-            if (isTikaPolymorphicType(beanClass)) {
-                LOG.debug("Registering wrapper serializer for polymorphic 
type: {}",
-                        beanClass.getName());
-                return new WrapperObjectSerializer<>(serializer, mapper);
-            }
-
-            return serializer;
-        }
-
-        private boolean shouldSkip(Class<?> beanClass) {
-            // Skip primitives and their wrappers
-            if (beanClass.isPrimitive()) {
-                return true;
-            }
-
-            // Skip common JDK types
-            String name = beanClass.getName();
-            if (name.startsWith("java.") || name.startsWith("javax.")) {
-                return true;
-            }
-
-            // Skip arrays
-            if (beanClass.isArray()) {
-                return true;
-            }
-
-            // Skip abstract types (we want to wrap concrete implementations, 
not the abstract types themselves)
-            if (beanClass.isInterface() || 
Modifier.isAbstract(beanClass.getModifiers())) {
-                return true;
-            }
-
-            return false;
-        }
-
-        /**
-         * Checks if this class should be wrapped with type information during 
serialization.
-         * Only types registered in the component registry are wrapped - this 
excludes
-         * container types (like CompositeMetadataFilter) that are not in the 
registry.
-         */
-        private boolean isTikaPolymorphicType(Class<?> beanClass) {
-            // Only wrap types that have a registered friendly name in the 
registry
-            return ComponentNameResolver.getFriendlyName(beanClass) != null;
-        }
-    }
-
-    /**
-     * Serializer that wraps objects with their type name.
-     * Output format: {"type-name": {...properties...}}
-     */
-    private static class WrapperObjectSerializer<T> extends JsonSerializer<T> {
-
-        private final JsonSerializer<T> delegate;
-        private final ObjectMapper mapper;
-
-        @SuppressWarnings("unchecked")
-        WrapperObjectSerializer(JsonSerializer<?> delegate, ObjectMapper 
mapper) {
-            this.delegate = (JsonSerializer<T>) delegate;
-            this.mapper = mapper;
-        }
-
-        @Override
-        public void serialize(T value, JsonGenerator gen, SerializerProvider 
serializers)
-                throws IOException {
-            if (value == null) {
-                gen.writeNull();
-                return;
-            }
-
-            // Get the friendly name (guaranteed to exist since we only wrap 
registered types)
-            String typeName = 
ComponentNameResolver.getFriendlyName(value.getClass());
-
-            // Write wrapper: {"type-name": {...}}
-            gen.writeStartObject();
-            gen.writeFieldName(typeName);
-            delegate.serialize(value, gen, serializers);
-            gen.writeEndObject();
-        }
-    }
-}

Reply via email to