CustomClassSerializationTest.java
/*
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Locale;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.jupiter.api.Test;
import org.apache.tika.config.loader.TikaObjectMapperFactory;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.filter.MetadataFilter;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.serialization.serdes.ParseContextDeserializer;
import org.apache.tika.serialization.serdes.ParseContextSerializer;
/**
* Tests that custom classes can be serialized/deserialized via JSON configs.
* <p>
* With the jsonConfigs approach, serialization works via JSON strings stored
* in ParseContext. Custom classes are deserialized at runtime.
*/
public class CustomClassSerializationTest {
/**
* Example custom metadata filter that uppercases all values.
* This simulates a user's custom class (e.g., in package com.acme).
*/
public static class MyUpperCasingMetadataFilter extends MetadataFilter {
private String prefix = "";
public MyUpperCasingMetadataFilter() {
}
public MyUpperCasingMetadataFilter(String prefix) {
this.prefix = prefix;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
@Override
public void filter(java.util.List<Metadata> metadataList, ParseContext parseContext) {
for (Metadata metadata : metadataList) {
for (String name : metadata.names()) {
String[] values = metadata.getValues(name);
metadata.remove(name);
for (String value : values) {
metadata.add(name, prefix + value.toUpperCase(Locale.ROOT));
}
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MyUpperCasingMetadataFilter)) return false;
MyUpperCasingMetadataFilter that = (MyUpperCasingMetadataFilter) o;
return prefix.equals(that.prefix);
}
@Override
public int hashCode() {
return prefix.hashCode();
}
}
private ObjectMapper createMapper() {
ObjectMapper mapper = TikaObjectMapperFactory.getMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(ParseContext.class, new ParseContextDeserializer());
module.addSerializer(ParseContext.class, new ParseContextSerializer());
mapper.registerModule(module);
return mapper;
}
@Test
public void testJsonConfigRoundTrip() throws Exception {
// Create a ParseContext with JSON config
ParseContext pc = new ParseContext();
pc.setJsonConfig("my-filter", "{\"prefix\":\"TEST_\"}");
// Serialize
ObjectMapper mapper = createMapper();
String json = mapper.writeValueAsString(pc);
// Verify JSON contains the config
assertTrue(json.contains("my-filter"), "JSON should contain the config key");
assertTrue(json.contains("TEST_"), "JSON should contain the prefix value");
// Deserialize
ParseContext deserialized = mapper.readValue(json, ParseContext.class);
// Verify the JSON config is preserved
assertTrue(deserialized.hasJsonConfig("my-filter"));
String deserializedJson = deserialized.getJsonConfig("my-filter").json();
assertTrue(deserializedJson.contains("TEST_"));
}
@Test
public void testCustomClassDeserialization() throws Exception {
// Test that a custom class can be deserialized from JSON
// This is done via ConfigDeserializer.getConfig() which uses Jackson
ParseContext pc = new ParseContext();
pc.setJsonConfig("my-filter", "{\"prefix\":\"CUSTOM_\"}");
// Use ConfigDeserializer to get and deserialize the config
// This simulates what a custom component would do
ObjectMapper mapper = createMapper();
String jsonConfig = pc.getJsonConfig("my-filter").json();
MyUpperCasingMetadataFilter filter = mapper.readValue(jsonConfig, MyUpperCasingMetadataFilter.class);
assertNotNull(filter);
assertEquals("CUSTOM_", filter.getPrefix());
// Verify the filter works
Metadata metadata = new Metadata();
metadata.add("test", "value");
java.util.List<Metadata> metadataList = new java.util.ArrayList<>();
metadataList.add(metadata);
filter.filter(metadataList);
assertEquals("CUSTOM_VALUE", metadata.get("test"));
}
}