1

I am trying to check for bean scopes, a prototype injected within singleton bean. When i use @Lookup annotation it is throwing null pointer exception.

thows null pointer at singletonBean class...Actually the return null should be overrided by cglib and should return the prototype scoped bean right...

AppConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import Bean.ProtoBean;
import Bean.SingletonBean;

@Configuration
 public class AppConfiguration {

@Bean
@Scope("prototype")
public ProtoBean protoBean() {
    return new ProtoBean();
}

@Bean
@Scope("singleton")
public SingletonBean singletonBean() {
    return new SingletonBean();
}

}

SingletonBean.java

@Component
public class SingletonBean {

public SingletonBean() {
    System.out.println("SingletonBean");
}

public ProtoBean fromProto() {
    ProtoBean protoBean = getProtoBean();
//throws nullpointer here
    System.out.println("beans is here: "+protoBean.hashCode());
    return protoBean;
}

@Lookup
public ProtoBean getProtoBean() {
    return null;
}

}

App.java

public class App 
{
 public static void main( String[] args )
{
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfiguration.class);
    SingletonBean sb = ctx.getBean(SingletonBean.class);
    ProtoBean pb = sb.fromProto();

    SingletonBean sb1 = ctx.getBean(SingletonBean.class);
    ProtoBean pb1 = sb1.fromProto();

    if(pb.equals(pb1)) {
        System.out.println("Equal Proto");
    } else {
        System.out.println("Unequal Proto");
    }

    ctx.close();


}
}
BeeHive
  • 23
  • 3
  • well, you call the method getProto() which when you look at your current implementation always returns null. So on the next line when you call protoBean.hashCode you actually cvall null.getHashCode hwich throws a nullpointer exception – meaningqo Oct 21 '19 at 12:45
  • @meaningqo, no, it's not so naive. (S)he's trying to have Spring overriding that null-returning (https://www.baeldung.com/spring-lookup), which normally works, but there are cases where it's problematic, see my answer. – zakmck Mar 10 '20 at 00:28

2 Answers2

1

I used to do the same thing with this approach, then, for some unknown reason it stopped working, yielding the same NPE problem. I believe Spring has problems with replacing your own implementation with the GCLIB-compiled one.

At the end, I've used the factory method approach, ie, the client bean has the Spring application context and uses it to return the desired dependant in getProtoBean(). This is less straightforward than using @Lookup, but seems to be more reliable.

zakmck
  • 2,715
  • 1
  • 37
  • 53
0

I have next case:

Thrown exception at @PostConstruct of prototype bean and after, always returned null in @Lookup method.

@Scope(SCOPE_PROTOTYPE)
@Component
public class PrototypeBean {

    @PostConstruct
    public void init() {
        sometimesThrownException();
    }
}

@Service
public class SingletoneBean{

    @Lookup
    protected PrototypeBean getPrototypeBean() {
        return null;
    } 
}

Exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'prototypeBean': Invocation of init method failed; nested exception is java.lang.NullPointerException
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:415)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:227)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1175)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:420)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:350)
        at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$LookupOverrideMethodInterceptor.intercept(CglibSubclassingInstantiationStrategy.java:245)
        at ru.open.obo.imports.service.importer.ImporterFactoryImpl$$EnhancerBySpringCGLIB$$42f89ab8.payment1cImporter(<generated>)
        at ru.open.obo.imports.service.importer.ImporterFactoryImpl.getImporter(ImporterFactoryImpl.java:29)
        at ru.open.obo.imports.service.ImportServiceImpl.processImport(ImportServiceImpl.java:326)
        at ru.open.obo.imports.service.ImportServiceImpl.processImport(ImportServiceImpl.java:307)
        at ru.open.obo.imports.service.ImportServiceImpl$$FastClassBySpringCGLIB$$5260e96c.invoke(<generated>)

To fix this behavior, I catch exceptions at @PostContruct method:

@Scope(SCOPE_PROTOTYPE)
@Component
public class PrototypeBean {

    @PostConstruct
    public void init() {
        try {
            sometimesThrownException();
        } catch (Exception e) {
            log.error("Error at initialize prototype", e);
            context.setIsHasUnexpectedError(true);
        }
    }
}

org.springframework.boot:2.3.2.RELEASE

io.spring.dependency-management:1.0.8.RELEASE

zbender
  • 357
  • 1
  • 14