users@jersey.java.net

Re: [Jersey] Issue with SpringServlet

From: Martin Grotzke <martin.grotzke_at_freiheit.com>
Date: Wed, 09 Jul 2008 00:09:06 +0200

Hi Peter,

if I understood you correctly, you want to configure multiple beans for
the same class.

For this issue we introduced the "value" attribute of the @Inject
annotation. With this it's possible to have multiple spring beans of the
same class which can be used like this:


    @Inject( "bean1" )
    private Bean _bean1;
    @Inject( "bean2" )
    private Bean _bean2;


    <bean id="bean1" class="some.spring.Bean" />
    <bean id="bean2" class="some.spring.Bean" />


Does this solve your issue, or did I get s.th. wrong?

Cheers,
Martin


On Tue, 2008-07-08 at 11:53 -0700, Peter Liu wrote:
> Hi,
>
> I have been trying out the spring-jersey integration and ran into an
> issue where the
> SpringServlet will not work if I configure multiple beans, one for the
> root resource class and one for
> each subclass of the root class. The SpringServlet.getBeanName() will
> throw an exception
> since it thinks that there are multiple beans configured for the same
> class.
>
> I made some changes to SpringServlet.getBeanName() (see attached file).
> In the case where there are multiple bean names returned for a given class,
> before throwing an error, I look for the bean instance that has the exact
> same class as the one being looked up. With this change, I am able to
> make application work.
>
> I would like to submit this change to jersey-spring. Please let me know
> if the change
> is acceptable or there is a better way to solve this problem.
>
>
> Thanks.
>
> Peter
> plain text document attachment (SpringServlet.java)
> /*
> * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
> *
> * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
> *
> * The contents of this file are subject to the terms of the Common Development
> * and Distribution License("CDDL") (the "License"). You may not use this file
> * except in compliance with the License.
> *
> * You can obtain a copy of the License at:
> * https://jersey.dev.java.net/license.txt
> * See the License for the specific language governing permissions and
> * limitations under the License.
> *
> * When distributing the Covered Code, include this CDDL Header Notice in each
> * file and include the License file at:
> * https://jersey.dev.java.net/license.txt
> * If applicable, add the following below this CDDL Header, with the fields
> * enclosed by brackets [] replaced by your own identifying information:
> * "Portions Copyrighted [year] [name of copyright owner]"
> */
> package x.service;
>
> import com.sun.jersey.spi.service.ComponentContext;
> import java.io.IOException;
> import java.lang.annotation.Annotation;
> import java.lang.reflect.Constructor;
> import java.lang.reflect.InvocationTargetException;
> import java.util.Arrays;
> import java.util.Collection;
> import java.util.Iterator;
>
> import javax.servlet.ServletException;
> import javax.servlet.ServletRequest;
> import javax.servlet.ServletResponse;
>
> import org.apache.commons.logging.Log;
> import org.apache.commons.logging.LogFactory;
> import org.springframework.aop.framework.Advised;
> import org.springframework.aop.support.AopUtils;
> import org.springframework.context.ApplicationContext;
> import org.springframework.context.ConfigurableApplicationContext;
> import org.springframework.web.context.WebApplicationContext;
> import org.springframework.web.context.support.WebApplicationContextUtils;
>
> import com.sun.jersey.api.core.ResourceConfig;
> import com.sun.jersey.spi.container.WebApplication;
> import com.sun.jersey.spi.container.servlet.ServletContainer;
> import com.sun.jersey.spi.inject.Inject;
> import com.sun.jersey.spi.service.ComponentProvider;
> import java.lang.reflect.Proxy;
>
> /**
> * TODO: DESCRIBE ME<br>
> * Created on: Apr 3, 2008<br>
> *
> * @author <a href="mailto:martin.grotzke_at_freiheit.com">Martin Grotzke</a>
> * @version $Id$
> */
> public class SpringServlet extends ServletContainer {
>
> private static final long serialVersionUID = 5686655395749077671L;
> private static final Log LOG = LogFactory.getLog(SpringServlet.class);
>
> public static class SpringComponentProvider implements ComponentProvider {
>
> /* (non-Javadoc)
> * @see com.sun.ws.rest.spi.service.ComponentProvider#getInjectableInstance(java.lang.Object)
> */
> public <T> T getInjectableInstance(T instance) {
> if (AopUtils.isAopProxy(instance)) {
> final Advised aopResource = (Advised) instance;
> try {
> @SuppressWarnings("unchecked")
> final T result = (T) aopResource.getTargetSource().getTarget();
>
> return result;
> } catch (Exception e) {
> LOG.fatal("Could not get target object from proxy.", e);
> throw new RuntimeException("Could not get target object from proxy.", e);
> }
> } else {
> return instance;
> }
> }
> private ConfigurableApplicationContext springContext;
>
> public SpringComponentProvider(ConfigurableApplicationContext springContext) {
> this.springContext = springContext;
> }
>
> public <T> T getInstance(Scope scope, Class<T> clazz)
> throws InstantiationException, IllegalAccessException {
> return getInstance(null, scope, clazz);
> }
>
> public <T> T getInstance(Scope scope, Constructor<T> constructor,
> Object[] parameters)
> throws InstantiationException, IllegalArgumentException,
> IllegalAccessException, InvocationTargetException {
>
> return getInstance(null, scope, constructor.getDeclaringClass());
>
> }
>
> public <T> T getInstance(ComponentContext cc, Scope scope, Class<T> clazz)
> throws InstantiationException, IllegalAccessException {
> final Autowire autowire = clazz.getAnnotation(Autowire.class);
> if (autowire != null) {
> if (LOG.isDebugEnabled()) {
> LOG.debug("Creating resource class " + clazz.getSimpleName() + " annotated with @" + Autowire.class.getSimpleName() + " as spring bean.");
> }
> /* use createBean to have a fully initialized bean, including
> * applied BeanPostProcessors (in contrast to #autowire()).
> */
> final Object result = springContext.getBeanFactory().createBean(clazz,
> autowire.mode().getSpringCode(), autowire.dependencyCheck());
>
> return clazz.cast(result);
> }
>
> final String beanName = getBeanName(cc, clazz, springContext);
>
> if (beanName == null) {
> return null;
> }
>
> /* if the scope is null, this means that jersey simply doesn't know what's
> * the scope of this dependency, so it's left to the application...
> */
> if (scope == Scope.Undefined || scope == Scope.Singleton && springContext.isSingleton(beanName) || scope == Scope.PerRequest && springContext.isPrototype(beanName)) {
> if (LOG.isDebugEnabled()) {
> LOG.debug("Retrieving bean '" + beanName + "' for resource class " + clazz.getSimpleName() + " from spring.");
> }
> Object result = springContext.getBean(beanName);
>
> if (result instanceof Proxy && result instanceof Advised) {
> try {
> result = ((Advised) result).getTargetSource().getTarget();
> } catch (Exception ex) {
> return null;
> }
> }
>
> return clazz.cast(result);
> } else {
> return null;
> }
>
> }
>
> public void inject(Object instance) {
> }
> };
>
> @Override
> protected void initiate(ResourceConfig rc, WebApplication wa) {
> try {
> final WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
>
> wa.initiate(rc, new SpringComponentProvider((ConfigurableApplicationContext) springContext));
> } catch (RuntimeException e) {
> LOG.error("Got exception while trying to initialize", e);
> throw e;
> }
> }
>
> /* (non-Javadoc)
> * @see javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
> */
> @Override
> public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
> LOG.debug("Starting...");
> try {
> super.service(req, res);
> } catch (RuntimeException e) {
> LOG.error("Caught exception.", e);
> }
> LOG.debug("Finished.");
> }
>
> private static String getBeanName(ComponentContext cc, Class<?> c, ApplicationContext springContext) {
> System.out.println("getBeanName() c = " + c + " cc = " + cc);
>
> boolean annotatedWithInject = false;
> if (cc != null) {
> final Inject inject = getAnnotation(cc.getAnnotations(), Inject.class);
> if (inject != null) {
> annotatedWithInject = true;
>
> if (inject.value() != null && !inject.value().equals("")) {
> System.out.println("inject.value = " + inject.value());
> return inject.value();
> }
>
> }
> }
>
> final String names[] = springContext.getBeanNamesForType(c);
>
> if (names.length == 0) {
> return null;
> } else if (names.length == 1) {
> return names[0];
> } else {
> for (int i = 0; i < names.length; i++) {
> String name = names[i];
> Object bean = springContext.getBean(name);
> Class clazz = null;
>
> if (bean instanceof Advised) {
> clazz = ((Advised) bean).getTargetSource().getTargetClass();
> } else {
> clazz = bean.getClass();
> }
>
> if (clazz == c) {
> return name;
> }
> }
> final StringBuilder sb = new StringBuilder();
> sb.append("There are multiple beans configured in spring for the type ").append(c.getName()).append(".");
>
>
> if (annotatedWithInject) {
> sb.append("\nYou should specify the name of the preferred bean at @Inject: Inject(\"yourBean\").");
> } else {
> sb.append("\nAnnotation information was not available, the reason might be because you're not using " +
> "@Inject. You should use @Inject and specifiy the bean name via Inject(\"yourBean\").");
> }
>
> sb.append("\nAvailable bean names: ").append(toCSV(names));
>
> throw new RuntimeException(sb.toString());
> }
> }
>
> private static <T extends Annotation> T getAnnotation(Annotation[] annotations,
> Class<T> clazz) {
> if (annotations != null) {
> for (Annotation annotation : annotations) {
> if (annotation.annotationType().equals(clazz)) {
> return clazz.cast(annotation);
> }
> }
> }
> return null;
> }
>
> static <T> String toCSV(T[] items) {
> if (items == null) {
> return null;
> }
> return toCSV(Arrays.asList(items));
> }
>
> static <I> String toCSV(Collection<I> items) {
> return toCSV(items, ", ", null);
> }
>
> static <I> String toCSV(Collection<I> items, String separator, String delimiter) {
> if (items == null) {
> return null;
> }
> if (items.isEmpty()) {
> return "";
> }
> final StringBuilder sb = new StringBuilder();
> for (final Iterator<I> iter = items.iterator(); iter.hasNext();) {
> if (delimiter != null) {
> sb.append(delimiter);
> }
> final I item = iter.next();
> sb.append(item);
> if (delimiter != null) {
> sb.append(delimiter);
> }
> if (iter.hasNext()) {
> sb.append(separator);
> }
> }
> return sb.toString();
> }
> }
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net