2017-02-14 11 views
3

Iは、その応答キャメルケースのJSON値であるコントローラを有しています。これで新しいバージョンのコードを書き直しました。必要な応答はsnake_caseにあります。条件に基づいてスプリングメッセージコンバータを適用する方法は?

Iは、予想通り、私は春とその作業と、この変換器を登録したsetPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

public class ResponseJSONConverter extends MappingJackson2HttpMessageConverter { 

@Autowired 
public ResponseJSONConverter(ObjectMapper objectMapper) { 
    setObjectMapper(objectMapper); 
    } 
} 

を設定するメッセージ変換と変更されたオブジェクトマッパーを追加しました。今、古いエンドポイントをcamelCaseに戻して、コンシューマーと新しいエンドポイントとの下位互換性をsnake_caseで戻したいと思います。

Iはスネークケースプロパティにキャメルケースを設定せずに、簡単なオブジェクトマッパーともう一つのメッセージ・コンバータを有することを試みたとスプリングに登録されています。 Springコンフィグレーションで宣言された順序に基づいて、1つのメッセージコンバータのみが適用されます。

我々はこれを達成することができます方法はありますか?条件に基づいてメッセージコンバータを読み込んでいますか?

EDIT

を追加しました私の春のconfigファイル

<beans xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:mvc="http://www.springframework.org/schema/mvc" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 
     xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context.xsd 
     http://www.springframework.org/schema/mvc 
     http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 

<bean id="moneySerializer" class="api.serialize.MoneySerializer"/> 
    <bean id="moneyDeserializer" class="api.serialize.MoneyDeserializer"/> 
    <bean id="serializationModule" class="api.serialize.SerializationModule"> 
     <constructor-arg index="0" ref="moneySerializer"/> 
     <constructor-arg index="1" ref="moneyDeserializer"/> 
    </bean> 

    <bean id="customObjectMapper" class="api.serialize.CustomObjectMapper" primary="true"> 
     <constructor-arg ref="serializationModule"/> 
    </bean> 
    <mvc:annotation-driven> 
     <mvc:message-converters register-defaults="true"> 
      <bean class="api.serialize.ResponseJSONConverterCamelCaseToSnakeCase" > 
       <constructor-arg ref="customObjectMapper"/> 
      </bean> 
      <bean class="api.serialize.ResponseJSONConverter"> 
       <constructor-arg ref="objectMapper"/> 
      </bean> 
     </mvc:message-converters> 

    </mvc:annotation-driven> 

    <bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/> 

</beans> 

EDIT 2.0

私servlet.xml

<mvc:annotation-driven> 
    <mvc:message-converters register-defaults="true"> 
     <bean class="com.tgt.promotions.api.serialize.ServiceJSONConverter"/> 
    </mvc:message-converters> 
</mvc:annotation-driven> 

CustomMessageConverter

public class ServiceJSONConverter extends MappingJackson2HttpMessageConverter { 

    @Autowired 
    public ServiceJSONConverter(SnakeCaseObjectMapper snakeCaseObjectMapper) { 
     setObjectMapper(snakeCaseObjectMapper); 
    } 
} 

カスタムオブジェクトマッパー

@Component 
public class SnakeCaseObjectMapper extends ObjectMapper { 
    @Autowired 
    public SnakeCaseObjectMapper(PropertyNamingStrategy propertyNamingStrategy) { 
     setSerializationInclusion(JsonInclude.Include.NON_NULL); 
     setPropertyNamingStrategy(propertyNamingStrategy); 
    } 
} 

カスタムプロパティは、代わりに2つの異なるオブジェクト・マッパーを有するので、私が作成し提案する戦略

@Component 
public class CustomPropertyNamingStrategy extends PropertyNamingStrategy { 

    @Autowired 
    private HttpServletRequest request; 

    private final PropertyNamingStrategy legacyStrategy = PropertyNamingStrategy.LOWER_CASE; 
    private final PropertyNamingStrategy defaultStrategy = PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES; 


    @Override 
    public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) { 
     return getStrategy().nameForConstructorParameter(config, ctorParam, defaultName); 
    } 

    @Override 
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { 
     return getStrategy().nameForField(config, field, defaultName); 
    } 

    @Override 
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return getStrategy().nameForGetterMethod(config, method, defaultName); 
    } 

    @Override 
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) { 
     return getStrategy().nameForSetterMethod(config, method, defaultName); 
    } 

    private PropertyNamingStrategy getStrategy() { 
     if (isLegacyEndpoint(request)) { 
      return legacyStrategy; 
     } else { 
      return defaultStrategy; 
     } 
    } 

    private boolean isLegacyEndpoint(HttpServletRequest request) { 
     return request != null && request.getRequestURL() != null && !request.getRequestURL().toString().contains("/v3"); 
    } 
} 
+0

スプリングXMLの設定やサポートコードを追加してください。 –

答えて

0

の命名cuで要求コンテキストにアクセスすることにより、エンドポイントURLを使用して

  1. public class AwesomePropertyNamingStrategy extends PropertyNamingStrategy { 
    
        private PropertyNamingStrategy legacyStrategy = PropertyNamingStrategy.LOWER_CASE; 
        private PropertyNamingStrategy defaultStrategy = PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES; 
    
        @Override 
        public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) { 
        return getStrategy().nameForConstructorParameter(config, ctorParam, defaultName); 
        } 
    
        // TODO: implement other nameForXXX methods 
    
        private PropertyNamingStrategy getStrategy() { 
        if (isLegacyEndpoint()) { 
         return legacyStrategy; 
        } else { 
         return defaultStrategy; 
        } 
        } 
    
        private boolean isLegacyEndpoint() { 
        // TODO: get hold of the RequestContext or some other thead-local context 
        // that allows you to know it's an old or a new endpoint 
        return false; 
        } 
    } 
    

    あなたがレガシーと新しいモードを切り替えるための方法を考え出す必要があります。それに応じて2つの他の戦略を使用してPropertyNamingStrategyのSTOM実装、古いエンドポイントが異なる応答オブジェクトを使用する場合にはいくつかの方法

  2. は、代わりにすべての古いクラスでレガシー/正常または独自のカスタム@LegacyResponse注釈を決定するために変換されているオブジェクトのクラスを使用します。
+0

返信いただきありがとうございます。私はあなたが何を提案したかを試みました。私はメッセージコンバータを作成し、customObjectMapperを渡し、あなたが示唆したようにAwesomePropertyNamingStrategyを設定しました。しかし、私が得る応答は、small caseとsnake_caseの両方の戦略が混在しています。これを解決するために何かする必要がありますか? – Pramod

+0

あなたが思いついた解決策、特に従来のものと新しいものを区別する部分を共有できますか? –

+0

私は、クラスでHttpServletRequestリクエストをautowiringしており、SpringからAwesomePropertyNamingStrategyをコンポーネントとしてロードしています。 – Pramod

0

まあ、何も多くの試みの後に働きました。最後に、2つの異なるサーブレットを定義しました。 1つはバージョンなし、もう1つはv1バージョンです。

ウェブ。XML

 <servlet> 
      <servlet-name>snake-case</servlet-name> 
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
      <load-on-startup>1</load-on-startup> 
     </servlet> 

     <servlet-mapping> 
      <servlet-name>snake-case</servlet-name> 
      <url-pattern>/v1</url-pattern> 
     </servlet-mapping> 

     <servlet> 
      <servlet-name>camel-case</servlet-name> 
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
      <load-on-startup>1</load-on-startup> 
     </servlet> 

     <servlet-mapping> 
      <servlet-name>camel-case</servlet-name> 
      <url-pattern>/</url-pattern> 
     </servlet-mapping> 

したがって2つのサーブレットヘビケース-servlet.xmlとキャメルケース-servlet.xmlを定義しました。さて、/ V1の*との任意の要求に対して、snakeCaseObjectMapperが使用されている

ヘビケース-servlet.xml

<mvc:annotation-driven> 
     <mvc:message-converters register-defaults="true"> 
      <bean class="com.tgt.promotions.api.serialize.DataJSONConverter"> 
      <constructor-arg ref="snakeCaseObjectMapper"/> 
      </bean> 
     </mvc:message-converters> 
    </mvc:annotation-driven> 

キャメルケース-servlet.xml

<mvc:annotation-driven> 
     <mvc:message-converters register-defaults="true"> 
      <bean class="com.tgt.promotions.api.serialize.DataJSONConverter"> 
      <constructor-arg ref="objectMapper"/> 
      </bean> 
     </mvc:message-converters> 
    </mvc:annotation-driven> 

とその他の要求に対しては、デフォルトのオブジェクトマッパーが使用されます。

関連する問題