facebookarchive / swift

An annotation-based Java library for creating Thrift serializable types and services.
Apache License 2.0
900 stars 297 forks source link

Custom codec / support for classes without @ThriftStruct annotation #277

Closed jaycyb closed 6 years ago

jaycyb commented 8 years ago

Hi guys, I am having difficulties using Swift on a ThriftStruct taking a joda DateTime as parameter:

@ThriftStruct
public class Foo
{
    private final DateTime time;

    @ThriftConstructor
    public Foo(DateTime time)
    {
        this.time = time;
    }
}

This gives an error since DateTime is not annotated with @ThriftStruct.

I suppose I am not expected to own all the code in a ThriftStruct right? So I guess my question is... what is the intended way to extend Swift codecs to support a case like this?

Thanks!!

jaycyb commented 8 years ago

I would like to add some things I have been experimenting with:

1/ binding a custom thift codec like so

Guice.createInjector(new AbstractModule()
    {
        @Override
        protected
        void configure()
        {
            ThriftCodecBinder
                .thriftCodecBinder(binder())
                .bindCustomThriftCodec(new CustomThriftCodec(DateTime.class));
        }
    }, /*...*/)
    .getInstance(MyService.class);

2/ Annotating joda DateTime with @ThriftStruct at runtime with javassist

I got some progress but I am now stuck with an error deep in the code generated by ThriftCodecByteCodeGenerator at runtime for my Foo struct above.

Exception in thread "main" com.google.common.util.concurrent.ExecutionError: com.google.common.util.concurrent.ExecutionError: java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    $wift/FooCodec.write(LFoo;Lorg/apache/thrift/protocol/TProtocol;)V @49: invokevirtual
  Reason:
    Type 'org/joda/time/DateTime' (current frame, stack[3]) is not assignable to 'java/nio/ByteBuffer'
  Current Frame:
    bci: @49
    flags: { }
    locals: { '$wift/FooCodec', 'Foo', 'org/apache/thrift/protocol/TProtocol', 'com/facebook/swift/codec/internal/TProtocolWriter' }
    stack: { 'com/facebook/swift/codec/internal/TProtocolWriter', 'java/lang/String', integer, 'org/joda/time/DateTime' }
  Bytecode:
  ......    
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.getConstructor(Class.java:1825)
    at com.facebook.swift.codec.internal.compiler.ThriftCodecByteCodeGenerator.<init>(ThriftCodecByteCodeGenerator.java:182)
    at com.facebook.swift.codec.internal.compiler.CompilerThriftCodecFactory.generateThriftTypeCodec(CompilerThriftCodecFactory.java:59)
    at com.facebook.swift.codec.ThriftCodecManager$1.load(ThriftCodecManager.java:108)
    at com.facebook.swift.codec.ThriftCodecManager$1.load(ThriftCodecManager.java:102)

Is there a neater way to do this?

jaycyb commented 8 years ago

_Update_ I was able to have a 2-ways method calls with a joda DateTime parameter or result.

My current solution is to bind a ThriftCodecFactory to a custom implementation + 2/ above.

Experiment 1/ above with bindCustomThriftCodec() didn't help because ThriftCatalog.isSupportedStructFieldType(Type) returns false, although the custom codec is loaded by ThriftCatalog. Could this be a bug?

Still it feels like I'm going against the intended usage of swift-codec .

Can anyone point out what I am missing?

jylin commented 7 years ago

I'm running into the same issue. I think it is a bug that the custom codec does not seem to work for ThriftField.