Guice dependency injector Null pointer exception - java

I am used the following code in java.I don't know what I did Wrong here.
My main file is:look and check
package com.sample.test;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class mymain {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppInjectory());
ApplicationExample obj = injector.getInstance(ApplicationExample.class);
obj.sendMessage();
}
}
My interface is:look and check
package com.sample.test;
public interface MessageService {
boolean sendMessage(String msg, String receipient);
}
My config file is look and check
package com.sample.test;
import com.google.inject.AbstractModule;
public class AppInjectory extends AbstractModule {
#Override
protected void configure() {
bind(MessageService.class).to(EmailService.class);
}
}
my application file is:look and check
package com.sample.test;
import javax.inject.Inject;
public class ApplicationExample {
private MessageService service;
#Inject
public void setService(MessageService svc){
this.service=svc;
}
public void sendMessage() {
System.out.println(“I am here”);
service.sendMessage(“welcome”, “java”);
}
}
my service class is :look and check
package com.sample.test;
//import com.google.inject.Singleton;
import javax.inject.Singleton;
#Singleton
public class EmailService implements MessageService {
public boolean sendMessage(String msg, String receipient) {
//some fancy code to send email
System.out.println(“Email Message sent to “+receipient+” with message=”+msg);
return true;
}
}
Here I am getting NUll pointer exception .What wrong I did here.?please help to fix this issue.I added the error stack trace here.
please look at it.
ERROR:
Exception in thread “main” I am here
java.lang.NullPointerException
at com.sample.test.ApplicationExample.sendMessage(ApplicationExample.java:16)
at com.sample.test.mymain.main(mymain.java:13)

The problem lies in this line:
ApplicationExample obj = injector.getInstance(ApplicationExample.class);
In your AppInjectory module you haven't bound your ApplicationExample interface to an implementation. Did you perhaps mean to do this (deducted from your module):
MessageService obj = injector.getInstance(MessageService.class);

Related

Loading a random class using reflection and have it register as a component in springboot

I have a random class in a random package that is loaded through reflection after the app launches, is there a way for it to be registered as a component under springboot and have annotations such as #Autowired and #Value etc work for that class.
It works when it is in the same package at launch time, but if introduce it thorough another jar at runtime (same package or not) it doesn't work.
Below are samples that don't work even if it is in the same jar. I can't change the app's configuration - it would defeat the "random package/random class" objective.
Code in Spring boot application package
package sample.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
// Code that starts app
//
//
try {
Thread.sleep(7000);
Class test = Class.forName("test.Test", true, Application.class.getClassLoader());
System.out.println(test.getMethod("getName").invoke(null)); //NPE
System.out.println(test.getMethod("getProfiles").invoke(null)); //NPE
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Test.java
package test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
#DependsOn("blaaaaaaaah")
#ComponentScan
public class Test {
#DependsOn("blaaaaaaaah")
public static String getName() {
return SpringGetter.instance.getApplicationName();
}
#DependsOn("blaaaaaaaah")
public static String[] getProfiles() {
String[] profiles = SpringGetter.instance.getEnv().getActiveProfiles();
if (profiles == null || profiles.length == 0) {
profiles = SpringGetter.instance.getEnv().getDefaultProfiles();
}
return profiles;
}
}
SpringGetter.java
package test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component("blaaaaaaaah")
public class SpringGetter implements InitializingBean {
public static SpringGetter instance;
#Value("${spring.application.name}")
private String applicationName;
#Autowired
private Environment env;
public SpringGetter() {
System.out.println("consASFJEFWEFJWDNFWJVNJSBVJWNCJWBVJNVJNVJSNJSNCSDJVNSVJtruct");
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
#PostConstruct
public void setInstance() {
instance = this;
}
#Override
public void afterPropertiesSet() throws Exception {
instance = this;
}
}
EDIT:
I managed to dynamically create the SpringGetter class as part of the same package as the Application class(the one with the #SpringBootApplication). I got Test.java to point to that dynamic class and yet no luck.
To simply inject fields into a POJO as if it were a Spring-managed bean, you can use something like the following:
#Component
public class BeanInitializer implements ApplicationContextAware {
private AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
public void initializeObject(Object pojo) {
beanFactory.autowireBean(pojo);
}
}
Note, however, that this only injects fields marked as #Autowired or #Injected. It does not create proxies that honor method interception strategies based on e.g. #Transactional, #Async, etc.
If you're using Spring 5, have a look at the registerBean() method from GenericApplicationContext. You can find an example here: https://www.baeldung.com/spring-5-functional-beans
The issue in your Test class may also be that you're not loading the Spring Boot context from the main class. You can use the SpringBootTest annotation for this.

How could I use abstract class on spring framework?

I'm the one leaning how to write a code using Spring Boot. Then when I tried to write a code that used abstract class, I got an error as below.
Description:
Parameter 0 of constructor in com.in28minutes.spring.practice.springmasterclasspractice.devicefactory.LaptopManufacturingProcess required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
Could you guys give me an advise how I could solve the error?
Spring Boot: v2.1.4
Java: 10.0.2
Maven: 3.6.0
SpringMasterClassPracticeDeviceFactoryApplication class
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class SpringMasterClassPracticeDeviceFactoryApplication {
private static Logger LOGGER = LoggerFactory.getLogger(SpringMasterClassPracticeDeviceFactoryApplication.class);
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication
.run(SpringMasterClassPracticeDeviceFactoryApplication.class, args);
ManufacturingImpl manufacturingImpl = applicationContext.getBean(ManufacturingImpl.class);
System.out.println(manufacturingImpl);
// manufacturingImpl.manifactureProduct("Laptop Process");
LOGGER.info("{}", manufacturingImpl);
}
}
ManufacturingImpl class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
public class ManufacturingImpl {
#Autowired
#Qualifier("laptop")
private GeneralManufacturingProcess generalManufacturingProcess;
public void manifactureProduct(String processName) {
System.out.println(generalManufacturingProcess);
generalManufacturingProcess.launchProcess();
}
}
GeneralManufacturingProcess class
public abstract class GeneralManufacturingProcess {
private String processName;
public GeneralManufacturingProcess(String processName) {
this.processName = processName;
}
public String getProcessName() {
return processName;
}
public void launchProcess() {
if (processName != null && !processName.isEmpty()) {
assembleDevice();
testDevice();
packageDevice();
storeDevice();
} else {
System.out.println("No process name was specified");
}
}
protected abstract void assembleDevice();
protected abstract void testDevice();
protected abstract void packageDevice();
protected abstract void storeDevice();
}
LaptopManufacturingProcess class
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("laptop")
public class LaptopManufacturingProcess extends GeneralManufacturingProcess {
public LaptopManufacturingProcess(String processName) {
super(processName);
}
#Override
protected void assembleDevice() {
System.out.println("Assembled laptop: " + getProcessName());
}
#Override
protected void testDevice() {
System.out.println("Tested laptop: " + getProcessName());
}
#Override
protected void packageDevice() {
System.out.println("Packaged laptop: " + getProcessName());
}
#Override
protected void storeDevice() {
System.out.println("Stored laptop: " + getProcessName());
}
}
There are Multiple ways to solve this. The problem is, that the Spring Framework is trying to create an instance of LaptopManufacturingProcess with the single constructor, which accepts a String. So the Framework is trying to autowire a Bean of type String into the constructor, which simply does not work.
Basically, what you can do is the following:
create a no-args constructor, and have it pass a hardcoded string to the parent constructor:
public LaptopManufacturingProcess() {
super("String");
}
Add an #Value-Annotation to read the String from a PropertySource:
public LaptopManufacturingProcess(#Value("${property.key.here}") String processName) {
super(processName);
}
Create a Factory Bean to create instances of GeneralManufacturingProcess on demand

wsgen exposes methods that are not annotated with #WebMethod

I have the following minimal webservice defined:
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
#WebService
public class DummyWS {
public static void main(String[] args) {
final String url= "http://localhost:8888/Dummy";
final Endpoint endpoint= Endpoint.create(new DummyWS());
endpoint.publish(url);
}
#WebMethod
public void putData(final String value) {
System.out.println("value: "+value);
}
#WebMethod
public void doSomething() {
System.out.println("doing nothing");
}
public void myInternalMethod() {
System.out.println("should not be exposed via WSDL");
}
}
As you can see I have two methods I want to expose, since they are annotated with #WebMethod: putData and doSomething.
But when running wsgen, it generates a WSDL that contains the myInternalMethod although it is not annotated.
Do I have a misconfiguration here? Why is a method exposed that is not annotated with #WebMethod?
OK, I found it. Per default all public methods are exposed. To exclude a method one must annotate it with #WebMethod(exclude=true).
This is quite a strange requirement, because it means that I only have to annotate those methods with #WebMethod that I do not want to expose.
This is the correct code then:
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
#WebService
public class DummyWS {
public static void main(String[] args) {
final String url= "http://localhost:8888/Dummy";
final Endpoint endpoint= Endpoint.create(new DummyWS());
endpoint.publish(url);
}
public void putData(final String value) {
System.out.println("value: "+value);
}
public void doSomething() {
System.out.println("doing nothing");
}
#WebMethod(exclude=true)
public void myInternalMethod() {
System.out.println("should not be exposed via WSDL");
}
}

ResourceResolverFactory is NULL (Adobe Experience Manager AEM)

I am trying to get a reference to the ResourceResolver from the ResourceResolverFactory as follows:
#Reference
private ResourceResolverFactory resourceResolverFactory;
public void someMethod() {
Map<String, Object> authenticationMap = new HashMap<String, Object>();
authenticationMap.put(ResourceResolverFactory.USER, "user");
authenticationMap.put(ResourceResolverFactory.PASSWORD, "pwd");
//This line returns NullPointerException
ResourceResolver resourceResolver = resourceResolverFactory.getResourceResolver(authenticationMap);
}
Can someone please tell me what I am doing wrong? The AEM API version v6.0.
So what I did was to create an Activator class that is called when the bundle is deployed and started. The Activator class then gets the instance of org.apache.sling.jcr.api.SlingRepository which we can use to connect to the JCR. Here is the activator code:
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(immediate = true, label = "Commons Activator")
public class Activator implements BundleActivator {
#Reference
private SlingRepository repository;
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
#Activate
#Override
public void start(BundleContext context) throws Exception {
logger.info(context.getBundle().getSymbolicName() + " started");
//My own factory class instance
ResourceResolverDiscoveryService rrf = ResourceResolverDiscoveryService.getInstance();
//Set the 'repository' in your factory class instance
rrf.setSlingRepositoryFactory(repository);
}
#Deactivate
#Override
public void stop(BundleContext context) throws Exception {
logger.info(context.getBundle().getSymbolicName() + " stopped");
}
}
Then in the class where I want to use JCR to store the data I did the following:
public class StoreInJCR {
public void store(Quote quote) throws LoginException, RepositoryException {
SlingRepository slingRepository = ResourceResolverDiscoveryService.getInstance().getSlingRepositoryFactory();
// GOT IT!!! Mission Accomplished
Session session = slingRepository.loginAdministrative(null);
Node root = session.getRootNode();
// Further code
.
.
}
}
Hope someone finds this useful.

Guice injecting Generic type

I'am trying to Inject generic type with Guice. I have Repository< T > which is located in the Cursor class.
public class Cursor<T> {
#Inject
protected Repository<T> repository;
So when I create Cursor< User >, I also want the Guice to inject my repository to Repository< User >. Is there a way to do this?
You have to use a TypeLiteral:
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<Repository<User>>() {}).to(UserRepository.class);
}
}
To get an instance of Cursor<T>, an Injector is required:
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
Cursor<User> instance =
injector.getInstance(Key.get(new TypeLiteral<Cursor<User>>() {}));
System.err.println(instance.repository);
}
}
More details in the FAQ.

Categories

Resources