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.
Related
I am trying to create a java + spring library (a seperate, reusable, application independent jar file) and use it in the application.
I show you a non-working example, that is already suitable to demonstrate my problem.
My problem is, that i have difficulties to autowire a repository by name and not by type.
The jar file logic is implemented here in one file called Library
package com.example;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.stereotype.Service;
public class Library {
#MappedSuperclass
public static class ChildEntity {
public String childAttribute;
}
#MappedSuperclass
public static class RootEntity<T extends ChildEntity> {
public String rootAttribute;
#OneToOne
public T childEntity;
}
#Service
public static class RootEntityService<T extends ChildEntity> {
#Autowired
#Qualifier(Library.REPOSITORY_BEAN_NAME)
private RootRepository<T> repository;
public RootEntity<T> findMyEntity() {
return this.repository.findByChildEntity();
}
}
#NoRepositoryBean
public static interface RootRepository<T extends ChildEntity> extends Repository<T, Long> {
public RootEntity<T> findByChildEntity();
}
public final static String REPOSITORY_BEAN_NAME = "entityRepository";
}
As you can see i have a RootEntity and a ChildEntity with a OneToOne relation.
The RootRepository is defined as #NoRepositoryBean, since Repository cannot have generic parameters.
The RootService is referencing for the RootRepository and i am trying to autowire by name and not type - using the #Qualifier annotation.
Here comes the application itself:
package com.example;
import javax.persistence.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.stereotype.Repository;
import com.example.Library.ChildEntity;
import com.example.Library.RootEntity;
import com.example.Library.RootEntityService;
import com.example.Library.RootRepository;
public class Application implements ApplicationRunner {
#Entity
public static class RealChildEntity extends ChildEntity {
public String realChildAttribute;
}
#Entity
public static class RealRootEntity extends RootEntity<RealChildEntity> {
}
#Repository(Library.REPOSITORY_BEAN_NAME)
public static interface RealRootRepository extends RootRepository<RealChildEntity> {
}
public static void main(final String[] args) throws Exception {
SpringApplication application;
application = new SpringApplication(ApplicationConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
}
#Autowired
private RootEntityService<RealChildEntity> rootEntityService;
#Override
public void run(final ApplicationArguments args) throws Exception {
this.rootEntityService.findMyEntity();
}
}
The RealChildEntity has an application specific attribute.
I define the RealRootRepository to be a real repository, without generic parameters. I have also defined a bean name for this component to refer to.
I also have an ApplicationConfig class to define the service bean and the repo:
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import com.example.Library.ChildEntity;
import com.example.Library.RootEntityService;
#Configuration
#EnableJpaRepositories(basePackageClasses = { Application.class })
public class ApplicationConfig {
#Bean(Library.REPOSITORY_BEAN_NAME)
public <T extends ChildEntity> RootEntityService<T> entityService() {
return new RootEntityService<T>();
}
}
If i execute this application, than spring gives me the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field repository in com.example.Library$RootEntityService required a bean of type 'com.example.Library$RootRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
- #org.springframework.beans.factory.annotation.Qualifier(value="entityRepository")
Spring tells me, that RootEntityService required a bean of type. Why by type?
I want a repository by name
What am i doing wrong?
How can i have a library service without extending it just because of the repository;
Thanks for your help in advance
I am trying to recast my SpringBoot application to functional bean registration form for faster application start up times as mentioned in the Spring documentation for Spring Cloud Functions. Below is the code referenced in the documentation:
#SpringBootConfiguration
public class DemoApplication implements ApplicationContextInitializer<GenericApplicationContext> {
public static void main(String[] args) {
FunctionalSpringApplication.run(DemoApplication.class, args);
}
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
#Override
public void initialize(GenericApplicationContext context) {
context.registerBean("demo", FunctionRegistration.class,
() -> new FunctionRegistration<>(uppercase())
.type(FunctionType.from(String.class).to(String.class)));
}
}
Here is my code attempting to follow the above exaple. The main difference is that my function is a separate class that implements the Java 8 function interface.
import com.example.functions.RockPaperScissors;
import com.example.model.Game;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.context.FunctionalSpringApplication;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
#Slf4j
#ComponentScan
#SpringBootConfiguration
public class Application implements ApplicationContextInitializer<GenericApplicationContext> {
private RockPaperScissors rockPaperScissors;
public static void main(String[] args) {
FunctionalSpringApplication.run(Application.class, args);
}
#Override
public void initialize(GenericApplicationContext applicationContext) {
applicationContext.registerBean(
"rpsFunction",
FunctionRegistration.class,
() ->
new FunctionRegistration<>(this.rockPaperScissors)
.type(FunctionType.from(Game.class).to(String.class)));
}
#Autowired
public void setRpsFunction(RockPaperScissors rockPaperScissors) {
this.rockPaperScissors = rockPaperScissors;
}
}
The issue I am having is java.lang.IllegalArgumentException: 'target' must not be null. I know this is due to no application context being found but not sure why FunctionalSpringApplication.run(DemoApplication.class, args); isn't creating that context.
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
I have extended my class from RepositoryRestMvcConfiguration according to documentation it has configureRepositoryRestConfiguration method which can be implemented but when I try to override this method I can't import it :|
Can anybody tell me Why this problem occurred?
EDIT : according to current version configureRepositoryRestConfiguration method is not avialble.. so what method should I used instead of this?
Here is my code
MSARepositoryRestMvcConfiguration.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
#Configuration
public class MSARepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MSARepositoryRestMvcConfiguration.class);
#Value("${static.path}")
private String staticPath;
// #Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
#Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setBasePath("/api");
// config.exposeIdsFor(User.class,Order.class,HeroRating.class,RiderLocation.class,OrderItem.class,Address.class,ShopDetail.class,PromoCode.class,RiderDuty.class,Criteria.class,Setting.class);
config.setReturnBodyForPutAndPost(true);
config.setReturnBodyOnCreate(true);
config.setReturnBodyOnUpdate(true);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
if(staticPath != null) {
LOG.info("Serving static content from " + staticPath);
registry.addResourceHandler("/photos/**").addResourceLocations("file:" + staticPath+"photos/");
registry.addResourceHandler("/").addResourceLocations("classpath:/static/");
}
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
Error
It gives an error on configureRepositoryRestConfiguration to remove override annotation
ErrorMessage
The method configureRepositoryRestConfiguration(RepositoryRestConfiguration) of type MSARepositoryRestMvcConfiguration must override or implement a supertype method
From the current reference documentation, Configuring Spring Data REST:
To customize the configuration, register a RepositoryRestConfigurer (or extend RepositoryRestConfigurerAdapter) and implement or override the configure…-methods relevant to your use case.
SDR configuration outside of RepositoryRestMvcConfiguration was addressed in DATAREST-621 and RepositoryRestConfigurer was introduced in this commit.
According to current version of spring document this method is not available so instead of `configureRepositoryRestConfiguration' we can override following method
#Configuration
public class MSARepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
public RepositoryRestConfiguration config() {
RepositoryRestConfiguration config = super.config();
config.setBasePath("/api");
config.exposeIdsFor(User.class);
return config;
}
}
Check the current configureRepositoryRestConfiguration definition at Interface RepositoryRestConfigurer.
Example form https://www.baeldung.com/spring-data-rest-serialize-entity-id:
#Configuration
public class RestConfiguration implements RepositoryRestConfigurer {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
config.exposeIdsFor(Person.class);
}
}
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);