users@jersey.java.net

Re: [Jersey] Issue with SpringServlet

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

Hi Peter,

please can you send a complete example for this, including the resource
classes? Perhaps we need to extend existing concepts of jerseys support
of IoC...

Thanx && cheers,
Martin


On Tue, 2008-07-08 at 16:32 -0700, Peter Liu wrote:
> Martin Grotzke wrote:
> > 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?
> >
>
> Unfortunately, I can't used the @Inject mechanism. What I am trying to
> do is to have a root
> singleton resource return a different "prototype" instance of a
> subresource when calling
> the subresource locator method. on the root resource. I am achieving
> this by using Spring's ServiceLocatorFactoryBean
> mechanism. It just happens that the subresource class can be a subclass
> of the root resource
> class. For example, my configuration may look as follow:
>
> <bean id="rootResource" class="x.RootResource"/>
> <bean id="subresource" class="x.SubclassOfRootResource" type="prototype"/>
>
> This will cause the getBeanName() to throw an exception because
> springContext.getBeanNamesForType(x.RootResource)
> will return both rootResource and subresource. However, in this case,
> it is really the rootResource that
> I want.
>
> Peter
>
>
> > 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
> >>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net