UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Adobe Launch】読み込んだスクリプトがminifiyされるのをやめたい

Adobe DTMというタグマネージャーのときはそうなっていなかったが、Adobe Launchというタグマネージャーにサービスが移行してからダウンロードされるスクリプトがminifyされるようになった

JSのダウンロードサイズが減るので嬉しいのだが、検証時にデバッグができず困ったのでminifiyしない方法を調べた

こちらの記事が参考になった

webanalyticsfordevelopers.com

結論、拡張子前のminを削除するとよいらしい

<script src="//assets.adobedtm.com/xxxxxx.min.js" async></script>
<script src="//assets.adobedtm.com/xxxxxx..js" async></script>

あとは、これのスクリプトをExperience Cloud デバッガーを使って埋め込む

やり方はこちらの記事に書いた   uga-box.hatenablog.com

これでデバッグすることができるようになった

ちなみに、ちゃんと読み込まれているかの確認はブラウザのコンソールで以下を実行するとわかるとのこと

_satellite.buildInfo || _satellite.buildDate

【Adobe Launch】検証用スクリプトをページに埋め込みたい

LaunchというAdobeのタグマネージャーを利用している

Launchでは管理するタグを修正した場合、公開フローに沿ってビルドして、テストして、実稼動用に承認するプロセスがある

experienceleague.adobe.com

上記のページより拝借した図  

このとき実稼動用に承認する前の状態のタグをテストしたいのでやり方を調べた

検証用スクリプトを手に入れる

Adobe Launchにログインすると Environmentsのタブから環境に応じたスクリプトを手に入れることができる

<script src="//assets.adobedtm.com/xxxxxxx-staging.min.js" async></script>

これを埋め込めばいいのだが、実稼動用と入れ替えるという修正はやりたくない

Experience Cloud デバッガーを使う

Adobeが出しているAdobe Experience Cloud Debuggerを使えば動的に埋め込むことができる

Adobe Experience Cloud Debugger - Chrome ウェブストア

experienceleague.adobe.com

Chrome限定になってしまうが、これで検証できるようになった

【Chrome】リクエストブロッキングしたい

非同期APIのレスポンスの結果を表示するコンテンツがある

このときレスポンスが表示されるまでスピナーを表示しておいてローディン中であることをユーザーに伝えているのだが、これがちゃんと表示されているかをテストしたい

いままでChromeのネットワークスロットリング設定で「低速3G」などにして確認していたが、どうにも結果が早いAPIの場合、一瞬しか表示されないので確実に止めたい

リクエスブロッキングで止める

調べたところ、Chromeにリクエスブロッキング機能があったのでこれを使った

表示された設定画面でブロックしたいURLを入力する

これで、ローディング画面の確認をすることができた

【Jackson】ObjectMapperであるクラスだけ別のPropertyNamingStrategiesにしたい

カスタマイズしたJackson2ObjectMapperBuilderを介して、ObjectMapperを独自の設定にすることができた

これでどこで使っても同じ設定になるわけだが、悲しいことにある外部APIのレスポンスだけ期待とは違うことに気づいた

具体的にはプロパティ名がLOWER_CAMEL_CASEであることを期待していたが、そのAPIだけUPPER_CAMEL_CASEになっている

先のカスタマイズしたJackson2ObjectMapperBuilderでは、LOWER_CAMEL_CASEになるような設定をしているためうまくマッピングされなかった

当然ながらDIしたObjectMapperに対してUPPER_CAMEL_CASEになるようにオーバーライドしてしまうと、他のAPIでこんどはアンマッチになってしまうので、 このAPIのレスポンスだけに対して行いたい

最速の解決策

UPPER_CAMEL_CASE用のbuilderを作ることも考えたが、もっとも簡単な解決方法は、そのDTO@JsonNamingアノテーションをつけてしまうことだった

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy.class)
@Data
public class FooApiResponse {
  private List<Foo> data;

  @JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy.class)
  @Data
  public static final class Foo {
    private Integer id;
    private String firstName;
    private String url;
  }

これで、このレスポンスだけUPPER_CAMEL_CASEとしてマッピングしてくれる

一点、内部クラスにもアノテーションをつけなければならないことに注意が必要だった

ObjectMapperBuilderをつくる

他の策としてUPPER_CAMEL_CASE用のbuilderをつくることを考えた

Jackson2ObjectMapperBuilderCustomizerにPropertyNamingStrategiesの設定をしているので、Customizerを呼び出して設定を上書きするようなことをしなくてはならない

たぶんこのような感じ

    @Bean
    @Primary
    public ObjectMapper mapper(List<Jackson2ObjectMapperBuilderCustomizer> customizerList,
   ApplicationContext context) {
      Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
      builder.applicationContext(context);
      for (Jackson2ObjectMapperBuilderCustomizer customizer: customizerList) {
        customizer.customize(builder);
      }
      return builder.build();
    }

    @Bean
    @Qualifier("upper")
    public ObjectMapper upperCaseMapper(List<Jackson2ObjectMapperBuilderCustomizer>
   customizerList, ApplicationContext context) {
      Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
      builder.applicationContext(context);
      for (Jackson2ObjectMapperBuilderCustomizer customizer: customizerList) {
        customizer.customize(builder);
      }
      builder.propertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
      return builder.build();
    }

【Spring Boot】Jackson2ObjectMapperBuilderCustomizerでObjectMapperBuilderをカスタマイズする

ObjectMapperをカスタマイズするためにJackson2ObjectMapperBuilderを使う場合、以下の設定がデフォルトで無効になっている

MapperFeature.DEFAULT_VIEW_INCLUSION DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES SerializationFeature.WRITE_DATES_AS_TIMESTAMPS

このときカスタマイズする設定との順番を制御したい

Jackson2ObjectMapperBuilderCustomizer

Jackson2ObjectMapperBuilderCustomizerを使えばJackson2ObjectMapperBuilderをカスタマイズでき、@Order アノテーションを使用することで、デフォルトの設定との順番を制御できるようになる

spring.pleiades.io

    @Bean
    @Order(Ordered.LOWEST_PRECEDENCE)
    @ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return new Jackson2ObjectMapperBuilderCustomizer() {

            @Override
            public void customize(Jackson2ObjectMapperBuilder builder) {
                builder.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
                builder.featuresToDisable(
                        SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
                        DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            }
        }
    }

Ordered.LOWEST_PRECEDENCEにすることで最後に設定されるようにしている

spring.pleiades.io

これで設定の順番を制御することができるようになった

【Spring Boot】Jackson2ObjectMapperBuilderでObjectMapperをカスタマイズする

JacksonのObjectMapperをカスタマイズしたいのでやり方を調べた

Bean登録して、@Primaryアノテーションをつける

一番シンプルな方法

@Bean
@Primary
public ObjectMapper objectMapper() {
    JavaTimeModule module = new JavaTimeModule();
    module.addSerializer(LOCAL_DATETIME_SERIALIZER);
    return new ObjectMapper()
      .setSerializationInclusion(JsonInclude.Include.NON_NULL)
      .registerModule(module);
}

Jackson2ObjectMapperBuilderを使う

Jacksonがクラスパス上にある場合は、Jackson2ObjectMapperBuilderが使える

docs.spring.io

これを使う場合は、以下の設定がデフォルトでされているとのこと

MapperFeature.DEFAULT_VIEW_INCLUSION is disabled DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES is disabled SerializationFeature.WRITE_DATES_AS_TIMESTAMPS is disabled

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
    return new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
      .serializationInclusion(JsonInclude.Include.NON_NULL);
}

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.html

これでカスタマイズすることができた

【Spring Boot】AutoConfigureで特定のライブラリがクラスパス上に存在する場合に適用するようにしたい

Spring BootのAutoConfigureでライブラリを作る際に、特定のライブラリがクラスパス上に存在する場合にBean定義した設定を適用するようにしたい

AutoConfigureとは
3rdパーティライブラリなどに対して、ある設定をした上でSpring上で利用したい場合に、それをあらかじめAutoConfigure用のBean定義をして用意しておくことで、Spring Bootが自動でそれらをインポートする仕組み

ライブラリに対する共通的な設定をコンテキストをまたがって行いたい場合に有用

このとき例えば、AutoConfigureでライブラリをBean設定していたにもかかわらず、3rdパーティライブラリをクラスパスにないままそのライブラリの利用者を利用しようとすると実行時にエラーになる可能性がある

なので、特定のライブラリがクラスパス上に存在する場合に適用するようにしたい

@ConditionalOnClassを使う

Spring Bootは、AutoConfigureに設定条件を指定できるようにアノテーションを提供している

クラスがクラスパス上に存在する場合に適用するようにする条件をつけるには@ConditionalOnClassがあり、これを利用するのがよさそう

spring.pleiades.io

例えば、ObjectMapperに対する設定をAutoConfigureでしたい場合、当然ObjectMapper.classがある場合に設定をしたいので、以下のようにアノテーションをつける

@Configuration(proxyBeanMethods = false
@ConditionalOnClass({ObjectMapper.class})
public class MyJacksonAutoConfiguration {

  @Bean
  @Order(Ordered.LOWEST_PRECEDENCE)
  @ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
  Jackson2ObjectMapperBuilderCustomizer myStandardObjectMapperBuilderCustomizer() {
    return new MyStandardObjectMapperBuilderCustomizer();
  }
}