Jersey;: Регистриране на инжектирани екземпляри ExceptionMapper чрез SpringServlet

Джърси: 1.12 Пролет: 3.11 JDK: 1.6.0_35 Tomcat: 6..0.33

Опитвам се да регистрирам екземпляри на ExceptionMapper за сървлет на Джърси, които са инстанцирани от контейнер на Spring IoC в контекста на SpringServlet, и се натъквам на старото изключение „Обхватът на класа на компонента X трябва да бъде единичен“ по време на сървлета на Джърси инициализация. Понастоящем не съм в състояние да публикувам действителния код, така че ще дам най-важното за внедряването, за да видя дали нещо очевидно ще изскочи на някого или мога да бъда насочен към някаква документация, която имам пропуснато.

Екземплярът ExceptionMapper е по същество както следва:

// ... package definitions omitted ...

@Provider
@Singleton
public class MyExceptionMapper
    implements ExceptionMapper<MyException>
{
    // ... injected attributes omitted ...

    @Override
    public Response toResponse(MyException exception)
    {
        // ... specific handling logic omitted ...

       return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
    }
}

Дефиницията на bean в applicationContext.xml е следната, която по подразбиране е с единичен обхват (и добавянето на изричен спецификатор на обхват изглежда не променя поведението):

<bean id="myExceptionMapper" class="my.package.MyExceptionMapper" />

Прослушвателят на контекстното зареждане на Spring и конфигурацията на SpringServlet в web.xml са по същество шаблонни и сървлетът ще зареди, инициализира и работи правилно с други атрибути за инжектиране, когато дефиницията на bean за MyExceptionMapper е коментирана извън applicationContext.xml. Но когато дефиницията на bean присъства в applicationContext.xml, получавам регистрационни съобщения за ефекта на:

SpringProviderFactory - Registering Spring bean, myExpectionMapper, of type my.package.MyExceptionMapper as a provider class
SpringProviderFactory - Registering Spring bean, myServiceController, of type my.package.MyServiceController as a root resource class
... other root resource classes loading ...
SpringServlet - Exception occurred when initialization
java.lang.RuntimeException: The scope of the component class my.package.MyExceptionMapper must be a singleton
  at som.sun.jersey.core.spi.component.ioc.IoCProviderFactory.wrap(...)

Опитах да поставя MyExceptionMapper в йерархията на сканираните пакети, за да бъде взет от SpringServlet по време на инициализация, и в отделна йерархия на пакети, и резултатите не се променят.

Всяка помощ или насоки по този въпрос ще бъдат много оценени.


person J. Gregory Wright    schedule 30.11.2012    source източник
comment
Проверихте ли отново дали използвате javax.inject.Singleton и анотациите javax.inject са активирани през пролетта?   -  person Nacho Coloma    schedule 10.01.2013


Отговори (6)


Попадна на същия проблем с интеграцията на Spring 3.2.3 и Jersey 2.3.1.

Това, което работи за мен, беше комбинация от две:

  1. Анотиране на Джърси @Provider клас с @Service или изрично създаване на сингълтон в xml контекст на приложение

    @Service //implies a singleton-scope
    @Provider
    public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {
    
        @Override
        public Response toResponse(Throwable exception) { //...
    
  2. Добавяне на пакет, който съдържа клас на доставчик към пакети от трико, предпочитам да направя това в клас MyApplication:

    public class MyApplication extends ResourceConfig {
    public MyApplication() {
        packages("com.mycompany.api.controller", "com.mycompany.api.jersey");
                //....
        }
    }
    
person mSolujic    schedule 09.10.2013

Моите ExceptionMappers са под структурата, в която правя сканиране на компоненти, а моите просто са анотирани с @Component за регистър Spring и @Provider за Jersey.

Моето сканиране на компоненти просто изглежда така:

<context:component-scan base-package="com.company.web"/>

и ExceptionMapper изглежда доста като твоя:

package com.mycompany.web.provider;

import com.mycompany.exception.SpecialException;
import com.mycompany.exception.Error;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
@Component
public class SpecialExceptionMapper implements ExceptionMapper<SpecialException> {

    @Autowired
    private MessageSource messageSource;

    @Override
    public Response toResponse(SpecialException exception) {

        Error error = new Error();


        error.errorMessage = messageSource.getMessage(exception.getResourceBundleKey(), exception.getArgs());

        return Response.status(Response.Status.BAD_REQUEST).
                entity(error).
                type(MediaType.APPLICATION_JSON).
                build();
    }
}
person Patrick    schedule 18.02.2013

Изричното добавяне на обхвата в пролетната конфигурация свърши работа за мен:

<bean id="exceptionMapper" class="my.pkg.MyExceptionMapper" scope="singleton" />
person Tim Van Laer    schedule 15.04.2013
comment
Добре, свърши работа, но какво означава това? Spring не счита ли всички bean-ове, дефинирани в XML, като singleton по подразбиране? Защо трябва изрично да посочим това? - person saratbeesa; 18.04.2014

Имах същия проблем, но с клас MessageReaderWriterProvider:

package my.provider.package;
...
@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json"})
@Produces({MediaType.APPLICATION_JSON, "text/json"})
public class ReRwProvider extends AbstractMessageReaderWriterProvider<Object> {
...
}

Решението беше да се добави пакетът от този клас в таг init-param за SpringServlet на Jersey в web.xml:

<init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>my.provider.package</param-value>
</init-param>

Имайте предвид, че не трябва да дефинирате този bean в контекста на Spring.

person catac    schedule 18.02.2013

Изглежда ми, че ExceptionMapper трябва да бъде конфигуриран като "singleton" с Spring. Ако искате да използвате конфигурацията на анотацията, трябва да обърнете внимание, защото Джърсито също има анотация "@Singleton" (с различно значение на javax.inject.Singleton, интерпретирано от spring) За да избегна объркване, предпочитам да използвам spring @Service анотация, което предполага единичен обхват... така че:

import org.springframework.stereotype.Service;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Service //implies a singleton-scope
@Provider
public class UnhandledExceptionMapper implements ExceptionMapper<Throwable> {

    @Override
    public Response toResponse(Throwable exception) {
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(new ErrorBean(false, exception.getMessage(), null))
                .build();
    }
}
person Fabio Bonfante    schedule 08.07.2013

Също така открих понякога, че coustom ExceptionMapper не работи и не винаги работи или не работи.

така че отстранявам грешки в изходния код на фланелката.

клас: org.glassfish.jersey.server.ServerRuntime, methed:mapException

 ...
 final long timestamp = tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING);
 **ExceptionMapper mapper = runtime.exceptionMappers.findMapping(throwable);**
 if (mapper != null) {
      request.getRequestEventBuilder().setExceptionMapper(mapper);

... ако картографът е нулев, персонализираният ExceptionMapper няма да работи.

клас: org.glassfish.jersey.internal.ExceptionMapperFactory methed: ExceptionMapperFactory

Exception Mapper :(има две изключения, преобразуващи едно и също изключение: java.lang.Exception)

org.glassfish.jersey.server.mvc.internal.ErrorTemplateExceptionMapper@6473fc2, клас java.lang.Exception

...

com.baidu.ssp.web.ws.exception.BaseExceptionMapper@7a84639c,клас java.lang.Exception

това е така, защото в MvcFeature:

@Override public boolean configure(final FeatureContext context) { final Configuration config = context.getConfiguration();

if (!config.isRegistered(ErrorTemplateExceptionMapper.class)) {
    context.register(ErrorTemplateExceptionMapper.class);
    context.register(new MvcBinder());

    return true;
}

return false;

} ErrorTemplateExceptionMapper също се добавя към ExceptionMapper.

така че променям моя персонализиран тип генеричност на MapperException: ExceptionMapper на ExceptionMapper

може би моята резолюция не е подходяща за вас, основният проблем е ExceptionMapper

person xfei6868    schedule 26.11.2014