2013-05-26 20 views
11

Jackson ObjectMapper Modülümün doğru şekilde kaydedilmesini sağlayamıyorum.Jackson ObjectMapper'ın Guice/Jersey ile bağlanması

Guice + Jersey + Jackson (FasterXML) yığını kullanıyorum.

Çeşitli sorulara göre ObjectMapper'ı nasıl özelleştireceğinizi takip ettim. Özellikle, bir @ javax.ws.rs.ext.Provider ve bir @ javax.inject.Singleton olarak işaretlenmiş bir ContextResolver bildirimi var. Tek başına bu yapılandırmayla, getContext() asla denir, bu yüzden mapper kayıtlı asla -

@Override 
protected Injector getInjector() { 

    Injector injector = Guice.createInjector(new DBModule(dataSource), 
      new ServletModule() 
      { 
       @Override 
       protected void configureServlets() { 


        // Mapper 
        bind(JacksonOMP.class).asEagerSingleton(); 

        // ... 

        Map<String, String> initParams = new HashMap<String, String>(); 
        initParams.put("com.sun.jersey.config.feature.Trace", 
          "true"); 
        initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true"); 

        serve("/services/*").with(
          GuiceContainer.class, 
          initParams); 
       } 
      }); 

    return injector; 
} 

Mapper Ancak

import javax.inject.Singleton; 
import javax.ws.rs.Produces; 
import javax.ws.rs.ext.ContextResolver; 
import javax.ws.rs.ext.Provider; 

@Provider 
@Singleton 
@Produces 
public class JacksonOMP implements ContextResolver<ObjectMapper> { 

    @Override 
    public ObjectMapper getContext(Class<?> aClass) { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
    } 
} 

tanımlanmış:

Ben çizgisinde bir GuiceServletContextListener var. Tipik bir rehberde sıkışıp kaldım - ek açıklamalar-gizem, aslında yapmam gereken şeylerin pratik olarak izlenemediği yer. Bahar kullanıcıları sadece bileşenin kaydedildiğini rapor eder ve kapsayıcıyı alır. Kendi javax.ws.rs.core.Application uygulamasının geçersiz kılınması hakkında görüşmelerde bulunma konusundaki görüşmeleri yanıtlayın.

This Ancak, bu DefaultResourceConfig() sabit kablolu GuiceContainer jarse-guice impementation olarak görünüyor:

@Override 
protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, 
     WebConfig webConfig) throws ServletException { 
    return new DefaultResourceConfig(); 
} 

Burada alt sınıf GuiceContainer gerekiyor? Yoksa eksik olduğum başka bir büyü açıklaması var mı?

Bu yapmak için oldukça yaygın bir şey gibi gözüküyor - Bu guice kombinasyonu ile ne kadar zor olduğunu gösterdiğine şaşırdım.

cevap

22

ben tipik Guice sıkıştım - bu aslında yapıyor olması gereken şey için pratikte izlenemez var ek açıklamalar-gizem. Yay kullanıcıları, yalnızca bileşenin kaydedildiğini bildirir ve kapsayıcı yalnızca onu alır.

Gerçekten excellent Guice documentation'u okumalısınız. Guice kullanımı çok kolaydır, çok az sayıda temel kavramı vardır. Sorununuz, Jersey JAX-RS bağımlılık enjeksiyonu ve Guice bağımlılık enjeksiyonunu karıştırmanızdır. GuiceContainer'u kullanıyorsanız, DI 0'unuzun no'lu tümünün Guess 'unu kullanacağınızı beyan edersiniz, bu yüzden JAX-RS ile değil Guice ile bağlayıcılar eklemeniz gerekir. ,

bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class).in(Singleton.class); 

Bu ObjectMapper bağlayacaktır:

import com.google.inject.Provider; 

public class ObjectMapperProvider implements Provider<ObjectMapper> { 
    @Override 
    public ObjectMapper get() { 
     final ObjectMapper mapper = new ObjectMapper(); 
     mapper.registerModule(new Hibernate4Module()); 
     return mapper; 
    } 
} 

Sonra modülüne bağlama tekabül eklemek gerekir:

Örneğin, bunun yerine düz Guice Provider kullanmalıdır, ContextResolver gerekmez ama Jersey'i Jackson ile kullanmak yeterli değil. Bir çeşit MessageBodyReader/MessageBodyWriter'a, örn. JacksonJsonProvider.Bunun için başka bir sağlayıcı gerekir:

public class JacksonJsonProviderProvider implements Provider<JacksonJsonProvider> { 
    private final ObjectMapper mapper; 

    @Inject 
    JacksonJsonProviderProvider(ObjectMapper mapper) { 
     this.mapper = mapper; 
    } 

    @Override 
    public JacksonJsonProvider get() { 
     return new JacksonJsonProvider(mapper); 
    } 
} 

Sonra bağlamak:

bind(JacksonJsonProvider.class).toProvider(JacksonJsonProviderProvider.class).in(Singleton.class); 

Bu yapmanız gereken tek şey - hayır sınıflara ihtiyaç vardır.

Kod boyutu en iyi duruma getirme için bir oda var. Ben sizin yerinizde olsam @Provides -Kullanılan kullanırsınız:

@Provides @Singleton 
ObjectMapper objectMapper() { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
} 

@Provides @Singleton 
JacksonJsonProvider jacksonJsonProvider(ObjectMapper mapper) { 
    return new JacksonJsonProvider(mapper); 
} 

Bu yöntemler örneğin sizin modüllerinden birine eklenmelidir anonim olarak ServletModule. Daha sonra ayrı sağlayıcı sınıflarına ihtiyacınız olmayacak.
BTW, ServletModule yerine JerseyServletModule kullanmalısınız, sizin için çok yararlı bağlantılar sağlar.

+0

Bu çok faydalıdır. Benim sorunum aslında * 2 * jacksons (hem codehaus sürümü hem de fastxml sürümü) vardı, bu yüzden yanlış tipte oldukları için objectmappers tamamen göz ardı edildi. – user340535

+0

Aynı bağımlılıklar çakışması sorunu yaşadım (codehaus + fasterxml): 'JsonIgnore' hiç çalışmıyordu. Benim durumumda, jackson codehaus (jackson-mapper-asl veya core-asl) bir azure documentdb paketi bağımlılığı ile bağlantılıydı ve en son (fastxml) sürümü sadece tutmak için tamamen kaldırıldı (pom hariç). Yorumunuz için @ user340535'e teşekkürler, bu da JacksonJsonProvider kancasını düzeltmeme yardımcı oldu! – boly38

+0

Herhangi bir nedenden dolayı, ek açıklamalara sahip sürüm, JerseyGuiceServletContextListener kullanarak Guice 4'te benimle çalışmaz. Buna ne sebep olabilir? Normal ciltleme ve ekstra sınıflar ile sorun olmadan çalışır. – Atais