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

Cole-Greer pushed a commit to branch simplePDT
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit f6e60c59c2879f8c0892ffda4378d2bfbf928330
Author: Cole Greer <[email protected]>
AuthorDate: Wed Jun 24 12:43:24 2026 -0700

    Make GraphBinary/GraphSON write path registry-aware for PDT dehydration
    
    Fixes the CompositePDT (0xF0) response-path gap where a provider type
    registered via a ProviderDefinedTypeAdapter but not annotated with
    @ProviderDefined could not be serialized when returned to the client.
    
    GraphBinaryWriter now accepts an optional ProviderDefinedTypeRegistry
    (parallel to GraphBinaryReader). When a class has no direct serializer
    and is not @ProviderDefined-annotated, the writer consults the registry
    by class and dehydrates via the adapter (adapter.toFields) into a
    ProviderDefinedType. Annotation-based auto-conversion is unchanged;
    adapter lookup is an additional resolution path.
    
    The GraphSON write path gains the same capability via
    PdtGraphSONSerializerProviderV4, which returns an adapter-based
    serializer for registry-registered classes. The registry is threaded
    through GraphBinaryMessageSerializerV4 and 
AbstractGraphSONMessageSerializerV4.
    
    The prior gap-validation test (which asserted the failure) is replaced by
    
GraphBinaryWriterPdtTest#shouldDehydrateRegisteredButUnannotatedTypeViaAdapterOnWritePath,
    asserting a successful adapter round-trip.
    
    tinkerpop-lka
    
    Assisted-by: Kiro:claude-opus-4.8
---
 .../structure/io/binary/GraphBinaryWriter.java     | 59 ++++++++++++++++++--
 .../structure/io/graphson/GraphSONMapper.java      |  7 +++
 .../io/graphson/GraphSONTypeIdResolver.java        | 11 ++++
 .../graphson/PdtGraphSONSerializerProviderV4.java  | 65 ++++++++++++++++++++++
 .../io/graphson/PdtGraphSONSerializersV4.java      | 54 ++++++++++++++++++
 .../io/graphson/PdtGraphSONSerializersV4Test.java  | 21 +++++++
 .../ser/AbstractGraphSONMessageSerializerV4.java   |  4 +-
 .../util/ser/GraphBinaryMessageSerializerV4.java   |  4 +-
 .../util/ser/binary/GraphBinaryWriterPdtTest.java  | 42 ++++++++++++++
 9 files changed, 259 insertions(+), 8 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryWriter.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryWriter.java
index ef4c07ccda..05fd63c366 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryWriter.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/GraphBinaryWriter.java
@@ -21,9 +21,13 @@ package org.apache.tinkerpop.gremlin.structure.io.binary;
 import 
org.apache.tinkerpop.gremlin.structure.io.binary.types.ProviderDefinedTypeSerializer;
 import 
org.apache.tinkerpop.gremlin.structure.io.binary.types.TransformSerializer;
 import org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedType;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeAdapter;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.Buffer;
 
 import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
 
 /**
  * Writes a value to a buffer using the {@link TypeSerializer} instances 
configured in the
@@ -44,6 +48,7 @@ import java.io.IOException;
  */
 public class GraphBinaryWriter {
     private final TypeSerializerRegistry registry;
+    private final ProviderDefinedTypeRegistry pdtRegistry;
     private final static byte VALUE_FLAG_NULL = 1;
     private final static byte VALUE_FLAG_NONE = 0;
     private final static byte VALUE_FLAG_ORDERED = 2;
@@ -57,7 +62,12 @@ public class GraphBinaryWriter {
     }
 
     public GraphBinaryWriter(final TypeSerializerRegistry registry) {
+        this(registry, null);
+    }
+
+    public GraphBinaryWriter(final TypeSerializerRegistry registry, final 
ProviderDefinedTypeRegistry pdtRegistry) {
         this.registry = registry;
+        this.pdtRegistry = pdtRegistry;
     }
 
     /**
@@ -75,9 +85,9 @@ public class GraphBinaryWriter {
 
         final Class<?> objectClass = value.getClass();
 
-        final TypeSerializer<T> serializer = (TypeSerializer<T>) 
registry.getSerializer(objectClass);
+        final TypeSerializer<T> serializer = (TypeSerializer<T>) 
getSerializerOrAdapterFallback(objectClass);
         if (serializer instanceof ProviderDefinedTypeSerializer && !(value 
instanceof ProviderDefinedType)) {
-            serializer.writeValue((T) ProviderDefinedType.from(value), buffer, 
this, nullable);
+            serializer.writeValue((T) dehydrateToPdt(value, objectClass), 
buffer, this, nullable);
             return;
         }
         serializer.writeValue(value, buffer, this, nullable);
@@ -94,13 +104,13 @@ public class GraphBinaryWriter {
         }
 
         final Class<?> objectClass = value.getClass();
-        final TypeSerializer<T> serializer = (TypeSerializer<T>) 
registry.getSerializer(objectClass);
+        final TypeSerializer<T> serializer = (TypeSerializer<T>) 
getSerializerOrAdapterFallback(objectClass);
 
         if (serializer instanceof ProviderDefinedTypeSerializer && !(value 
instanceof ProviderDefinedType)) {
-            // Convert @ProviderDefined-annotated object to 
ProviderDefinedType, then re-enter write().
+            // Convert to ProviderDefinedType (via annotation or adapter), 
then re-enter write().
             // On re-entry, ProviderDefinedType.class is directly registered 
in the registry,
             // and the instanceof guard prevents double-wrapping.
-            write((T) ProviderDefinedType.from(value), buffer);
+            write((T) dehydrateToPdt(value, objectClass), buffer);
             return;
         }
 
@@ -155,4 +165,43 @@ public class GraphBinaryWriter {
         buffer.writeByte(VALUE_FLAG_BULK);
     }
 
+    /**
+     * Attempts to get a serializer for the given class. If no serializer is 
found and the pdtRegistry
+     * has an adapter for the class, returns the CompositePDT serializer.
+     */
+    @SuppressWarnings("unchecked")
+    private <DT> TypeSerializer<DT> getSerializerOrAdapterFallback(final 
Class<?> type) throws IOException {
+        try {
+            return (TypeSerializer<DT>) registry.getSerializer(type);
+        } catch (final IOException e) {
+            if (pdtRegistry != null && 
pdtRegistry.getAdapterByClass(type).isPresent()) {
+                return (TypeSerializer<DT>) 
registry.getSerializer(DataType.COMPOSITE_PDT);
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Dehydrates a value to a {@link ProviderDefinedType} using annotation 
reflection or an adapter from the
+     * pdtRegistry.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private ProviderDefinedType dehydrateToPdt(final Object value, final 
Class<?> objectClass) {
+        // Prefer annotation-based conversion
+        if 
(objectClass.isAnnotationPresent(org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefined.class))
 {
+            return ProviderDefinedType.from(value);
+        }
+        // Fall back to adapter-based conversion
+        if (pdtRegistry != null) {
+            final Optional<ProviderDefinedTypeAdapter<?>> opt = 
pdtRegistry.getAdapterByClass(objectClass);
+            if (opt.isPresent()) {
+                final ProviderDefinedTypeAdapter adapter = opt.get();
+                final Map<String, Object> fields = adapter.toFields(value);
+                return new ProviderDefinedType(adapter.typeName(), fields);
+            }
+        }
+        // Should not reach here since getSerializerOrAdapterFallback already 
validated
+        return ProviderDefinedType.from(value);
+    }
+
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
index 6877b67c69..3b9b46f884 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapper.java
@@ -105,6 +105,9 @@ public class GraphSONMapper implements Mapper<ObjectMapper> 
{
         if ((version == GraphSONVersion.V4_0 || version == 
GraphSONVersion.V3_0 || version == GraphSONVersion.V2_0) &&
                 typeInfo != TypeInfo.NO_TYPES) {
             final GraphSONTypeIdResolver graphSONTypeIdResolver = new 
GraphSONTypeIdResolver();
+            if (pdtRegistry != null && version == GraphSONVersion.V4_0) {
+                graphSONTypeIdResolver.setPdtRegistry(pdtRegistry);
+            }
             final TypeResolverBuilder typer = new 
GraphSONTypeResolverBuilder(version)
                     .typesEmbedding(this.typeInfo)
                     .valuePropertyName(GraphSONTokens.VALUEPROP)
@@ -161,6 +164,10 @@ public class GraphSONMapper implements 
Mapper<ObjectMapper> {
             // this provider toStrings all unknown classes and converts keys 
in Map objects that are Object to String.
             final DefaultSerializerProvider provider = new 
GraphSONSerializerProvider(version);
             om.setSerializerProvider(provider);
+        } else if (pdtRegistry != null) {
+            // For V4 with a pdtRegistry, set a provider that converts 
adapter-registered types to PDT
+            final DefaultSerializerProvider provider = new 
PdtGraphSONSerializerProviderV4(pdtRegistry);
+            om.setSerializerProvider(provider);
         }
 
         if (normalize)
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeIdResolver.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeIdResolver.java
index 08184d6566..0b535f8141 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeIdResolver.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeIdResolver.java
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.structure.io.graphson;
 
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.structure.Element;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
 import org.apache.tinkerpop.shaded.jackson.annotation.JsonTypeInfo;
 import org.apache.tinkerpop.shaded.jackson.core.type.TypeReference;
 import org.apache.tinkerpop.shaded.jackson.databind.DatabindContext;
@@ -42,6 +43,8 @@ public class GraphSONTypeIdResolver implements TypeIdResolver 
{
 
     private final Map<Class, String> typeToId = new HashMap<>();
 
+    private ProviderDefinedTypeRegistry pdtRegistry;
+
     // Override manually a type definition.
     public GraphSONTypeIdResolver addCustomType(final String name, final Class 
clasz) {
         if (Tree.class.isAssignableFrom(clasz)) {
@@ -65,6 +68,10 @@ public class GraphSONTypeIdResolver implements 
TypeIdResolver {
         return typeToId;
     }
 
+    public void setPdtRegistry(final ProviderDefinedTypeRegistry pdtRegistry) {
+        this.pdtRegistry = pdtRegistry;
+    }
+
     @Override
     public void init(final JavaType javaType) {
     }
@@ -77,6 +84,10 @@ public class GraphSONTypeIdResolver implements 
TypeIdResolver {
     @Override
     public String idFromValueAndType(final Object o, final Class<?> aClass) {
         if (!typeToId.containsKey(aClass)) {
+            // Check if pdtRegistry has an adapter for this class
+            if (pdtRegistry != null && 
pdtRegistry.getAdapterByClass(aClass).isPresent()) {
+                return 
typeToId.get(org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedType.class);
+            }
             // If one wants to serialize an object with a type, but hasn't 
registered
             // a typeID for that class, fail.
             throw new IllegalArgumentException(String.format("Could not find a 
type identifier for the class : %s. " +
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializerProviderV4.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializerProviderV4.java
new file mode 100644
index 0000000000..fb29453da5
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializerProviderV4.java
@@ -0,0 +1,65 @@
+/*
+ * 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.tinkerpop.gremlin.structure.io.graphson;
+
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializationConfig;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import 
org.apache.tinkerpop.shaded.jackson.databind.ser.DefaultSerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.SerializerFactory;
+
+/**
+ * A {@link DefaultSerializerProvider} for GraphSON V4 that returns a PDT 
adapter-based serializer
+ * for classes registered in the {@link ProviderDefinedTypeRegistry}.
+ */
+final class PdtGraphSONSerializerProviderV4 extends DefaultSerializerProvider {
+    private static final long serialVersionUID = 1L;
+    private final ProviderDefinedTypeRegistry pdtRegistry;
+    private final JsonSerializer<Object> pdtAdapterSerializer;
+
+    PdtGraphSONSerializerProviderV4(final ProviderDefinedTypeRegistry 
pdtRegistry) {
+        super();
+        this.pdtRegistry = pdtRegistry;
+        this.pdtAdapterSerializer = new 
PdtGraphSONSerializersV4.PdtAdapterJacksonSerializer(pdtRegistry);
+    }
+
+    private PdtGraphSONSerializerProviderV4(final SerializerProvider src,
+                                            final SerializationConfig config, 
final SerializerFactory f,
+                                            final ProviderDefinedTypeRegistry 
pdtRegistry,
+                                            final JsonSerializer<Object> 
pdtAdapterSerializer) {
+        super(src, config, f);
+        this.pdtRegistry = pdtRegistry;
+        this.pdtAdapterSerializer = pdtAdapterSerializer;
+    }
+
+    @Override
+    public JsonSerializer<Object> getUnknownTypeSerializer(final Class<?> 
aClass) {
+        if (pdtRegistry != null && 
pdtRegistry.getAdapterByClass(aClass).isPresent()) {
+            return pdtAdapterSerializer;
+        }
+        return super.getUnknownTypeSerializer(aClass);
+    }
+
+    @Override
+    public PdtGraphSONSerializerProviderV4 createInstance(final 
SerializationConfig config,
+                                                          final 
SerializerFactory jsf) {
+        return new PdtGraphSONSerializerProviderV4(this, config, jsf, 
pdtRegistry, pdtAdapterSerializer);
+    }
+}
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
index de116f54aa..03e686917c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.structure.io.graphson;
 
 import org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedType;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeAdapter;
 import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
 import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
 import org.apache.tinkerpop.shaded.jackson.core.JsonParser;
@@ -27,10 +28,12 @@ import 
org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext;
 import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
 import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer;
 import 
org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdScalarSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
 
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * GraphSON V4 serializers for {@link ProviderDefinedType}.
@@ -113,4 +116,55 @@ final class PdtGraphSONSerializersV4 {
             return true;
         }
     }
+
+    /**
+     * A serializer that converts raw objects to {@link ProviderDefinedType} 
using a registered adapter,
+     * then serializes the resulting PDT in the standard CompositePdt format.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    static class PdtAdapterJacksonSerializer extends StdSerializer<Object> {
+
+        private final ProviderDefinedTypeRegistry registry;
+
+        PdtAdapterJacksonSerializer(final ProviderDefinedTypeRegistry 
registry) {
+            super(Object.class);
+            this.registry = registry;
+        }
+
+        @Override
+        public void serialize(final Object value, final JsonGenerator 
jsonGenerator,
+                              final SerializerProvider serializerProvider) 
throws IOException {
+            final ProviderDefinedType pdt = toPdt(value);
+            jsonGenerator.writeStartObject();
+            jsonGenerator.writeStringField("type", pdt.getName());
+            jsonGenerator.writeFieldName("fields");
+            jsonGenerator.writeStartObject();
+            for (final Map.Entry<String, Object> entry : 
pdt.getFields().entrySet()) {
+                jsonGenerator.writeFieldName(entry.getKey());
+                jsonGenerator.writeObject(entry.getValue());
+            }
+            jsonGenerator.writeEndObject();
+            jsonGenerator.writeEndObject();
+        }
+
+        @Override
+        public void serializeWithType(final Object value, final JsonGenerator 
jsonGenerator,
+                                      final SerializerProvider 
serializerProvider,
+                                      final 
org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer 
typeSerializer) throws IOException {
+            // Convert to ProviderDefinedType and delegate to its registered 
typed serializer
+            final ProviderDefinedType pdt = toPdt(value);
+            
serializerProvider.findTypedValueSerializer(ProviderDefinedType.class, true, 
null)
+                    .serialize(pdt, jsonGenerator, serializerProvider);
+        }
+
+        private ProviderDefinedType toPdt(final Object value) throws 
IOException {
+            final Optional<ProviderDefinedTypeAdapter<?>> opt = 
registry.getAdapterByClass(value.getClass());
+            if (!opt.isPresent()) {
+                throw new IOException("No adapter found for " + 
value.getClass().getName());
+            }
+            final ProviderDefinedTypeAdapter adapter = opt.get();
+            final Map<String, Object> fields = adapter.toFields(value);
+            return new ProviderDefinedType(adapter.typeName(), fields);
+        }
+    }
 }
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
index 20bf1f7238..fa29b1ba68 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/PdtGraphSONSerializersV4Test.java
@@ -205,6 +205,27 @@ public class PdtGraphSONSerializersV4Test extends 
AbstractGraphSONTest {
         assertEquals(1, result.getFields().get("x"));
     }
 
+    @Test
+    public void 
shouldDehydrateRegisteredButUnannotatedTypeViaAdapterOnWritePath() throws 
Exception {
+        final ProviderDefinedTypeRegistry registry = 
ProviderDefinedTypeRegistry.empty();
+        registry.register(new PointAdapter());
+
+        final ObjectMapper adapterMapper = GraphSONMapper.build()
+                .version(GraphSONVersion.V4_0)
+                .addCustomModule(GraphSONXModuleV4.build())
+                .typeInfo(TypeInfo.PARTIAL_TYPES)
+                .pdtRegistry(registry)
+                .create().createMapper();
+
+        final Point original = new Point(5, 9);
+        final ProviderDefinedType result = serializeDeserialize(adapterMapper, 
original, ProviderDefinedType.class);
+
+        assertNotNull(result.getHydrated());
+        assertTrue(result.getHydrated() instanceof Point);
+        assertEquals(5, ((Point) result.getHydrated()).x);
+        assertEquals(9, ((Point) result.getHydrated()).y);
+    }
+
     @Test
     public void shouldReturnRawPdtWhenTypeNotRegistered() throws Exception {
         final ProviderDefinedTypeRegistry registry = 
ProviderDefinedTypeRegistry.empty();
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
index 63c3893fb0..0fdf213b7d 100644
--- 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
+++ 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/AbstractGraphSONMessageSerializerV4.java
@@ -28,6 +28,7 @@ import 
org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONUtil;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV4;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
 import org.apache.tinkerpop.gremlin.util.Tokens;
 import org.apache.tinkerpop.gremlin.util.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.util.message.ResponseMessage;
@@ -77,7 +78,8 @@ public abstract class AbstractGraphSONMessageSerializerV4 
extends AbstractMessag
 
     private GraphSONMapper.Builder initBuilder() {
         final GraphSONMapper.Builder b = GraphSONMapper.build();
-        return 
b.addCustomModule(GraphSONXModuleV4.build()).version(GraphSONVersion.V4_0);
+        return 
b.addCustomModule(GraphSONXModuleV4.build()).version(GraphSONVersion.V4_0)
+                .pdtRegistry(ProviderDefinedTypeRegistry.create());
     }
 
     private GraphSONMapper.Builder applyMaxTokenLimits(final 
GraphSONMapper.Builder builder, final Map<String, Object> config) {
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
index 6f2e4c657f..67a4498ab4 100644
--- 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
+++ 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
@@ -68,7 +68,7 @@ public class GraphBinaryMessageSerializerV4 extends 
AbstractMessageSerializer<Gr
 
     public GraphBinaryMessageSerializerV4(final TypeSerializerRegistry 
registry, final ProviderDefinedTypeRegistry pdtRegistry) {
         reader = new GraphBinaryReader(registry, pdtRegistry);
-        writer = new GraphBinaryWriter(registry);
+        writer = new GraphBinaryWriter(registry, pdtRegistry);
         mapper = new GraphBinaryMapper(writer, reader);
 
         requestSerializer = new RequestMessageSerializer();
@@ -102,7 +102,7 @@ public class GraphBinaryMessageSerializerV4 extends 
AbstractMessageSerializer<Gr
 
         final TypeSerializerRegistry registry = builder.create();
         reader = new GraphBinaryReader(registry, 
ProviderDefinedTypeRegistry.create());
-        writer = new GraphBinaryWriter(registry);
+        writer = new GraphBinaryWriter(registry, 
ProviderDefinedTypeRegistry.create());
 
         requestSerializer = new RequestMessageSerializer();
     }
diff --git 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryWriterPdtTest.java
 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryWriterPdtTest.java
index e4483934d5..7576dbe306 100644
--- 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryWriterPdtTest.java
+++ 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryWriterPdtTest.java
@@ -22,8 +22,11 @@ import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.structure.io.Buffer;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
+import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry;
 import org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefined;
 import org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedType;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeAdapter;
+import 
org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeRegistry;
 import org.apache.tinkerpop.gremlin.util.ser.NettyBufferFactory;
 import org.junit.Test;
 
@@ -57,6 +60,21 @@ public class GraphBinaryWriterPdtTest {
         int value = 1;
     }
 
+    static class UnannotatedTypeAdapter implements 
ProviderDefinedTypeAdapter<UnannotatedType> {
+        @Override public String typeName() { return "UnannotatedType"; }
+        @Override public Class<UnannotatedType> targetClass() { return 
UnannotatedType.class; }
+        @Override public Map<String, Object> toFields(final UnannotatedType 
obj) {
+            final Map<String, Object> m = new LinkedHashMap<>();
+            m.put("value", obj.value);
+            return m;
+        }
+        @Override public UnannotatedType fromFields(final Map<String, Object> 
fields) {
+            final UnannotatedType t = new UnannotatedType();
+            t.value = (int) fields.get("value");
+            return t;
+        }
+    }
+
     @Test
     public void shouldAutoConvertAnnotatedObjectToPdt() throws IOException {
         final Buffer buffer = bufferFactory.create(allocator.buffer());
@@ -77,6 +95,30 @@ public class GraphBinaryWriterPdtTest {
         assertTrue(ex.getMessage().contains("UnannotatedType"));
     }
 
+    /**
+     * Verifies that a type registered via a {@link 
ProviderDefinedTypeAdapter} (without the {@link ProviderDefined}
+     * annotation) can be dehydrated on the write path by a registry-aware 
{@link GraphBinaryWriter} and then
+     * hydrated back by the reader through the same registry.
+     */
+    @Test
+    public void 
shouldDehydrateRegisteredButUnannotatedTypeViaAdapterOnWritePath() throws 
IOException {
+        final ProviderDefinedTypeRegistry pdtRegistry = 
ProviderDefinedTypeRegistry.empty();
+        pdtRegistry.register(new UnannotatedTypeAdapter());
+
+        final GraphBinaryWriter registryWriter = new 
GraphBinaryWriter(TypeSerializerRegistry.INSTANCE, pdtRegistry);
+        final GraphBinaryReader registryReader = new 
GraphBinaryReader(TypeSerializerRegistry.INSTANCE, pdtRegistry);
+
+        final UnannotatedType original = new UnannotatedType();
+        original.value = 42;
+
+        final Buffer buffer = bufferFactory.create(allocator.buffer());
+        registryWriter.write(original, buffer);
+        buffer.readerIndex(0);
+
+        final UnannotatedType result = registryReader.read(buffer);
+        assertEquals(42, result.value);
+    }
+
     @Test
     public void shouldNotDoubleWrapProviderDefinedType() throws IOException {
         final Map<String, Object> fields = new LinkedHashMap<>();

Reply via email to