前回のブログの続き、Lombokで生成されたDTOがなぜデシリアライズできないのかを調べる
うまくJSONがデシリアライズできない、ということで
前回の記事に書いた。
Payara micro触る(楽しようとしたらハマった話) - 京都行きたい
内部で取り込んでいるJacksonのバージョン的にもデシリアライズできるはずである。
なんでうまくデシリアライズできないのかを調べてみることにする。
(EclipseにEclipse Decompilerプラグインが入ってる前提で話を勧めます。)
mike-neck.hatenadiary.com
ここの記事を読む限りでは、Jacksonが使われるはずだ、と思っていました。
検証方法:トレース追っかける。
ROOT.warにしてる理由は蓮沼さんのブログの記事から。
Payara Micro のコンテキストルート - Promised Land
用意
EmbeddedでPayaraを立ち上げることにする。
コードはやんくさんのブログを参考に
Payara MicroProfileでぱやぱやする - Javaプログラマのはしくれダイアリー
public class Embedded { public static void main(String[] args) throws BootstrapException { PayaraMicro.getInstance() .addDeployment("build/libs/ROOT.war") .bootStrap(); } }
EclipseからデバッグモードでEmbeddedをJava Applicationとして起動します。
前回お茶を濁したリソースクラスにブレークポイントを貼ります。
(前回ワークアラウンドで作成したProviderクラスはProviderアノテーション外せば無効になるはずなので無効にしておきます。)
@Path("/example") public class Resource { @GET @Path("hello") public String hello(){ return "test"; } @GET @Path("user") @Produces(MediaType.APPLICATION_JSON) public User get(){ return new User("xx"); //ここにブレークポイントを貼る } @GET @Path("prisoner") @Produces(MediaType.APPLICATION_JSON) public Prisoner getPrisoner(){ return new Prisoner().setName("orekyuu"); } }
で、まぁブレークポイントを遡っていくと
Throwableをcatchしているところが見つかります。
org.glassfish.jersey.server.ServerRuntimeの334行目、のようです。
ここでEclipseの画面に
[Window] --> [Show View] --> [Expressions]で
式評価をできる画面を出しておきます。
以下の式を入力してみましょう
throwable.printStackTrace()
そしたらログでてきた以下のトレースに注目してみます。(部分的に抽出してます。)
MessageBodyWriterが見つかりません、とのことなので、まぁそういうことなのでしょう
WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteToを見てみます。
Caused by: org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class io.github.wreulicke.application.User, genericType=class io.github.wreulicke.application.User. at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:106) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:86)
/* */ public void aroundWriteTo(WriterInterceptorContext context) throws WebApplicationException, IOException { /* 228 */ WriterInterceptorExecutor.LOGGER.log(Level.SEVERE, LocalizationMessages.ERROR_NOTFOUND_MESSAGEBODYWRITER(context.getMediaType(), context.getType(), context.getGenericType())); /* */ WriterInterceptorExecutor.this.processedCount--; /* 230 */ WriterInterceptorExecutor.this.traceBefore((Object)null, MsgTraceEvent.WI_BEFORE); /* */ try { /* 232 */ TracingLogger tracingLogger = WriterInterceptorExecutor.this.getTracingLogger(); /* 233 */ if(tracingLogger.isLogEnabled(MsgTraceEvent.MBW_FIND)) { /* 234 */ tracingLogger.log(MsgTraceEvent.MBW_FIND, new Object[]{context.getType().getName(), context.getGenericType() instanceof Class?((Class)context.getGenericType()).getName():context.getGenericType(), context.getMediaType(), Arrays.toString(context.getAnnotations())}); /* */ /* */ /* */ /* */ /* */ } /* */ /* 241 */ MessageBodyWriter writer = this.workers.getMessageBodyWriter(context.getType(), context.getGenericType(), context.getAnnotations(), context.getMediaType(), WriterInterceptorExecutor.this); /* */ /* */ /* 244 */ if(writer == null) { /* */ /* */ /* 247 */ throw new MessageBodyProviderNotFoundException(LocalizationMessages.ERROR_NOTFOUND_MESSAGEBODYWRITER(context.getMediaType(), context.getType(), context.getGenericType())); /* */ } /* */
Exceptionを吐いた上のところの241行目にこんな記述が見つかります。
ではもう少し潜ってみます。
241行目にブレークポイントを仕掛けてみましょう。
再度エラーが発生するようにAPIを呼び出して
先程仕掛けたthis.workers.getMessageBodyWriterの部分に止まったところで
Step Intoで実装に潜っていきます。
org.glassfish.jersey.message.internal.MessageBodyFactoryの743行目前後に飛ぶと思います。
/* */ public <T> MessageBodyWriter<T> getMessageBodyWriter(Class<T> c, Type t, Annotation[] as, MediaType mediaType, PropertiesDelegate propertiesDelegate) { /* 743 */ MessageBodyWriter p = null; /* */ /* 745 */ if(this.legacyProviderOrdering.booleanValue()) { /* 746 */ if(mediaType != null) { /* 747 */ p = this._getMessageBodyWriter(c, t, as, mediaType, mediaType, propertiesDelegate); /* 748 */ if(p == null) { /* 749 */ p = this._getMessageBodyWriter(c, t, as, mediaType, MediaTypes.getTypeWildCart(mediaType), propertiesDelegate); /* */ } } /* */ /* 752 */ if(p == null) { /* 753 */ p = this._getMessageBodyWriter(c, t, as, mediaType, MediaType.WILDCARD_TYPE, propertiesDelegate); /* */ } /* */ } else { /* 756 */ p = this._getMessageBodyWriter(c, t, as, mediaType, this.writers, propertiesDelegate); /* */ } /* */ /* 759 */ return p; /* */ }
で、結局756行目が呼び出されるのでそちらの実装を見てみます。
/* */ private <T> MessageBodyWriter<T> _getMessageBodyWriter(Class<T> c, Type t, Annotation[] as, MediaType mediaType, List<WriterModel> models, PropertiesDelegate propertiesDelegate) { /* 770 */ MediaType lookupType = mediaType != null && !mediaType.getParameters().isEmpty()?new MediaType(mediaType.getType(), mediaType.getSubtype()):mediaType; /* */ /* */ /* */ /* 774 */ MessageBodyFactory.ModelLookupKey lookupKey = new MessageBodyFactory.ModelLookupKey(c, lookupType, null); /* 775 */ Object writers = (List)this.mbwLookupCache.get(lookupKey); /* 776 */ if(writers == null) { /* */ /* 778 */ writers = new ArrayList(); /* */ /* 780 */ Iterator tracingLogger = models.iterator(); while(tracingLogger.hasNext()) { WriterModel selected = (WriterModel)tracingLogger.next(); /* 781 */ if(this.isCompatible(selected, c, mediaType)) { /* 782 */ ((List)writers).add(selected); /* */ } } /* */ /* 785 */ Collections.sort((List)writers, new MessageBodyFactory.WorkerComparator(c, mediaType, null)); /* 786 */ this.mbwLookupCache.put(lookupKey, writers); /* */ }
で、ここで見るべきは775行目の後のwritersの中身です。
EclipseからVariablesの中身を見てみます。
WriterModelの中身を見てみるとproviderというキー項目があり
当方の環境では、「org.glassfish.jersey.moxy.json.internal.ConfigurableMoxyJsonProvider@5c43cb12」
というのが確認できると思います。
writers内部の他のModelを見てもJacksonが使われてるような痕跡は見当たりません。
と、言うわけで
中を見る感じだとJacksonは使われているようには見えません。
とりあえず今日はこんなところで。
デバッガでごり押しました。
P.S.
Jackson使われてませんでした。
以下のstackoverflow見る感じだと
元々GlassfishのほうでもデフォルトはMOXyなんですかね?
glassfish - Force Glassfish4 to use Jackson instead of Moxy - Stack Overflow