In the link:
How to instantiate an object using LambdaMetaFactory? it is mentioned how to instantiate a one-arg contrcutor using LambdaMetafactory.
I am trying to do the same for default-constructor but is failing with the below error:
Exception in thread "main" java.lang.AbstractMethodError: Method com/test/Main$$Lambda$1.apply(Ljava/lang/Object;)Ljava/lang/Object; is abstract
at com.test.Main$$Lambda$1/186370029.apply(Unknown Source)
at com.test.Main.test2(Main.java:29)
at com.test.Main.main(Main.java:14)
Code I am trying to run:
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Function;
public class Main {
public static void main(String[] args) throws Throwable {
long t2= System.nanoTime();
for(int i=0;i<10000;i++){
test2(TestClass.class.getName());
}
long t3= System.nanoTime();
System.out.println((t3-t2)*1e-9);
}
private static TestClass test2(String objclass)
throws Throwable {
Class clazz = Class.forName(objclass);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class));
Function<String, TestClass> constructor = (Function<String, TestClass>) LambdaMetafactory
.metafactory(lookup, "apply",MethodType.methodType(Function.class),
mh.type().generic(), mh, mh.type()).getTarget().invokeExact();
TestClass testClass = constructor.apply(objclass);
return testClass;
}
}
TestClass
import java.util.Collections;
import java.util.Map;
public class TestClass {
public Map<String, String> getContextMap() {
return Collections.emptyMap();
}
}
What am I doing wrong in order to invoke the default constructor using LambdaMetafactory?
Your default constructor takes no parameter. Change Function to Supplier:
private static TestClass test2(String objclass)
throws Throwable {
Class clazz = Class.forName(objclass);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class));
Supplier<TestClass> constructor = (Supplier<TestClass>) LambdaMetafactory.metafactory(
lookup, "get", MethodType.methodType(Supplier.class), mh.type().generic(), mh, mh.type()
).getTarget().invokeExact();
TestClass testClass = constructor.get();
return testClass;
}
Related
I am implementing AWS lambda function creating handler using Spring Cloud function AWS Adapter SpringBootRequestHandler. The functional bean registered in GenericApplicationContext is invoked, but autowiring of component class is giving NullPointer Exception.
I have tried #ComponentScan for base package at Spring Application.
Application class:
#Slf4j
#SpringBootApplication
#ComponentScan({ "com.poc.evthub" })
#EnableConfigurationProperties(EventHubProperties.class)
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {
public EventHubServerlessApplication() {
}
public static void main(String[] args) throws Exception {
FunctionalSpringApplication.run(EventHubServerlessApplication.class, args);
}
#Bean
public KinesisEventFunction ingestEvents() {
return new KinesisEventFunction();
}
#Override
public void initialize(GenericApplicationContext context) {
log.debug("======== initialize ========");
context.registerBean("ingestEvents", FunctionRegistration.class,
() -> new FunctionRegistration<Function<KinesisEvent, ApiResponse>>(ingestEvents())
.type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
}
}
Handler:
public class KinesisEventHandler extends SpringBootRequestHandler<KinesisEvent, ApiResponse> {
}
Functional Bean:
package com.poc.evthub.function;
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.poc.evthub.beans.ApiResponse;
import com.poc.evthub.constant.Constants;
import com.poc.evthub.service.IngestionServiceFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.function.Function;
#Slf4j
#Component
public class KinesisEventFunction implements Function<KinesisEvent, ApiResponse> {
private Context context = null;
#Autowired
private IngestionServiceFactory ingestionServiceFactory;
#Autowired
#Qualifier("targetExecutionContext")
public void setContext(Context context) {
log.info("Context: {}", context);
this.context = context;
}
#Override
public ApiResponse apply(final KinesisEvent kinesisEvent) {
log.info("KinesisEventFunction apply called...");
String sourceDomain = System.getenv(Constants.SYSENV.SOURCE_DOMAIN);
log.info("Source Domain = {}", sourceDomain);
if(null == kinesisEvent || null == kinesisEvent.getRecords()) {
log.error("Event contains no data. {}", System.lineSeparator());
//TODO build response NOT FOUND
return null;
}
else
log.info("Received {} records from {}. {}",
kinesisEvent.getRecords().size(),
kinesisEvent.getRecords().get(0).getEventSourceARN(),
System.lineSeparator());
log.info("ingestionServiceFactory = {}",ingestionServiceFactory);
ingestionServiceFactory.ingest();
return null;
}
}
Complete code and pom is uploaded at:
https://github.com/rjavaria/eventhub-serverless
KinesisEventFunction apply called...
Also able to read the environment value(source_domain) from lambda, and receiving Kinesis event record.
But #Autowired ingestionServiceFactory is null. I am injecting this component bean to delegate the business logic.
What is missed here, so spring is not able to inject this component bean?
Thanks in advance!
You could try manual injection of your IngestionServiceFactory bean into your function class via constructor or setter injection.
In your function class, add a constructor and remove #Autowired from your IngestionServiceFactory field, like:
...
public class KinesisEventFunction implements Function<KinesisEvent, ApiResponse> {
...
// No #Autowired here...
private final IngestionServiceFactory ingestionServiceFactory;
...
// The new constructor here...
public KinesisEventFunction(final IngestionServiceFactory pIngestionServiceFactory) {
this.ingestionServiceFactory = pIngestionServiceFactory;
}
...
}
Then in your main class (the one implementing ApplicationContextInitializer<GenericApplicationContext>), pass the reference to the factory when registering the function bean, like:
...
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {
...
#Autowired
private IngestionServiceFactory ingestionServiceFactory;
...
#Bean
public KinesisEventFunction ingestEvents() {
return new KinesisEventFunction(this.ingestionServiceFactory);
}
#Override
public void initialize(GenericApplicationContext context) {
log.debug("======== initialize ========");
context.registerBean("ingestEvents", FunctionRegistration.class,
() -> new FunctionRegistration<>(ingestEvents())
.type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
}
}
Or, as you are already manually registering the function bean with context.registerBean(), you could just:
...
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {
...
#Autowired
private IngestionServiceFactory ingestionServiceFactory;
...
#Override
public void initialize(GenericApplicationContext context) {
log.debug("======== initialize ========");
context.registerBean("ingestEvents", FunctionRegistration.class,
() -> new FunctionRegistration<>(new KinesisEventFunction(this.ingestionServiceFactory))
.type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
}
}
Please, let me know if it works!
Hi I am trying to load some database values at start time of spring boot application. I have autowired service, and in service i have autowired Dao. Below is the error.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'validationExpressionService': Unsatisfied dependency expressed through field 'validationExpressionDao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'IValidationExpressionDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.ril.nfg.dao.bean.ValidationExpression
I have added #EnitityScan #EnableJPARepository
FYI, Primary key in the case in String, hope that is ok.
Entity
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* The Class ValidationExpression.
*/
package com.ril.nfg.dao.bean;
#Entity
#Table(name = "VALIDATION_EXPRESSION")
public class ValidationExpression implements Serializable {
private static final long serialVersionUID = 9096950800262493651L;
private String validationId;
private String expression;
private String createdBy;
private Date createdOn;
private String description;
private String responseCode;
#Id
#Column(name = "VALIDATION_ID", nullable = false, length = 100)
public String getValidationId() {
return validationId;
}
public void setValidationId(String validationId) {
this.validationId = validationId;
}
#Column(name = "EXPRESSION", nullable = false, length = 200)
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
//remaining getters and setters
}
Repository
package com.ril.nfg.dao.repos;
import com.ril.nfg.dao.bean.ValidationExpression;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* The Interface IValidationExpressionDao.
*/
#Repository
public interface IValidationExpressionDao extends JpaRepository<ValidationExpression, String> {
}
Service
import java.util.List;
#Service
public class ValidationExpressionService {
#Autowired
IValidationExpressionDao validationExpressionDao;
public List<ValidationExpression> getAll() {
return validationExpressionDao.findAll();
}
}
Class with #Autwired Service
public class CacheModuleParam implements ApplicationContextAware{
private static List<ValidationExpression> validationExpressionList = null;
#Autowired
ValidationExpressionService validationExpressionService;
#Override
public void setApplicationContext(final ApplicationContext appContext) throws BeansException {
validationExpressionList = validationExpressionService.getAll();
}
}
Application Class
#ComponentScan(basePackages = {"com.ril.nfg"})
#EnableWebMvc
#EnableAutoConfiguration
#SpringBootApplication//(exclude={DataSourceAutoConfiguration.class})
#EnableJpaRepositories(basePackages="com.ril.nfg.dao.repos",entityManagerFactoryRef="oracleEntityManagerFactory")
//#EntityScan(basePackages = "com.ril.nfg.dao.bean")
public class NFGApplication {
public static void main(String[] args) {
SpringApplication.run(NFGApplication.class, args);
}
}
All solutions on internet focuses on #EntityScan. Please help me understand what is wrong with this code. Thanks in advance
Why do you have all this configuration? Simply put our application in the package tree one level above all the other classes and you can go with a class like this:
#SpringBootApplication
public class NFGApplication {
public static void main(String[] args) {
SpringApplication.run(NFGApplication.class, args);
}
}
Packages:
com.ril.nfg <- here you put NFGApplication
And all other classes in subpackages of com.ril.nfg
And then everything will work!
I have two classes in my test package: Bean, Demo2 and VerboseLoader.
Bean.java:
package test;
public class Bean {
}
VerboseLoader.java:
package test;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.NotFoundException;
import javassist.Translator;
public class VerboseLoader implements Translator{
#Override
public void start(ClassPool pool) throws NotFoundException, CannotCompileException {
}
#Override
public void onLoad(ClassPool pool, String classname) throws NotFoundException, CannotCompileException {
System.out.println("onLoad called for " + classname);
}
}
Demo2.java:
package test;
import javassist.*;
public class Demo2{
public static void main(String[] args) throws Throwable {
if(args.length >= 1){
Translator translator = new VerboseLoader();
ClassPool pool = ClassPool.getDefault();
Loader loader = new Loader(pool);
loader.addTranslator(pool, translator);
String[] pargs = new String[args.length-1];
System.arraycopy(args, 1, pargs, 0, pargs.length);
loader.run(args[0], pargs);
}
else{
System.out.println("Main args...");
}
}
}
will throw
onLoad called for Bean
Exception in thread "main" java.lang.ClassNotFoundException: Bean
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
at javassist.Loader.delegateToParent(Loader.java:431)
at javassist.Loader.loadClass(Loader.java:311)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
at javassist.Loader.run(Loader.java:284)
at test.Demo2.main(Demo2.java:21)
[Javassist 3.23.1-GA]
What am I doing wrong?
I've missed the package name before the className
loader.run("test."+args[0], pargs);
I'm trying to create a BeanFactory called TaskBeanFactory that I can Autowire into another prototype class that's running on a thread. I want a different instance of a bean returned by the Factory based on a taskName that i want to pass into it but when i start the application i get a null pointer exception because the taskName is null. I had a look at this article but i'm confused about how I should configure the Factory and then pass in the taskName.
The Factory:
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.stereotype.Component;
#Data
#Component
#NoArgsConstructor
public class TaskBeanFactory extends AbstractFactoryBean<GenericTask>{
private TaskNameEnum taskName;
public TaskBeanFactory(TaskNameEnum taskName) {
setSingleton(false);
}
#Override
public Class<?> getObjectType() {
return GenericTask.class;
}
#Override
protected GenericTask createInstance() throws Exception {
switch (taskName) {
case FILE_OPERATION:
return new FileTask();
case DATA_OPERATION:
return new DataTask();
default:
return new GenericTask();
}
}
}
The classes used by the Factory:
#Data
public class GenericTask {
private String idTask;
public void executeTask(Work work) {};
}
#Component
#Scope(value="prototype")
public class FileTask extends GenericTask {
#Override
public void executeTask(Work work) {
//some processing
}
}
#Component
#Scope(value="prototype")
public class DataTask extends GenericTask {
#Override
public void executeTask(Work work) {
//some processing
}
}
and the thread that's calling the Factory:
#Slf4j
#Data
#Scope("prototype")
#Component
public class WorkerThread implements Runnable {
#Autowired
private TaskBeanFactory taskBeanFactory;
#Autowired
private DataService dataService;
#Override
public void run() {
//iterate a Map of taskIds from the dataService
taskBeanFactory.setTaskName(TaskNameEnum.valueOf(taskEntry.getKey()));
GenericTask genericTask = taskBeanFactory.getObject();
//expecting genericTask to be of Type FileTask if called with one Key
//or of Type DataTask if called with another
}
}
}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MiParteTrabajoDao': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mydomain.repository.produccion.ParteTrabajoRepository com.mydomain.dao.produccion.ParteTrabajoDaoExample.parteRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mydomain.repository.produccion.ParteTrabajoRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.inject.Inject()}
package com.mydomain.repository;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
#NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
#Override
<S extends T> S save(S entity);
#Override
T findOne(ID primaryKey);
#Override
List<T> findAll();
#Override
long count();
#Override
void delete(T entity);
#Override
boolean exists(ID primaryKey);
}
and
package com.mydomain.repository.produccion;
public interface ParteTrabajoRepository extends CrudRepository<PParteTrabajo, PParteTrabajoPK> {
#Query(value = "select u from PParteTrabajo u where u.idParteTrabajo like %?1", nativeQuery = true)
public PParteTrabajo findByIdParteTrabajo(int idParteTrabajo);
}
and
package com.mydomain.dao.produccion;
public interface ParteTrabajoDaoI {
public List<PParteTrabajo> findAll();
}
and
package com.mydomain.dao.produccion;
#Repository("MiParteTrabajoDao")
public class ParteTrabajoDaoExample implements ParteTrabajoDaoI {
#Autowired
private ParteTrabajoRepository parteRepository;
#Override
public List<PParteTrabajo> findAll() {
final List<PParteTrabajo> lista = parteRepository.findAll();
return null;
}
}
and
package com.mydomain.services.produccion;
import com.mydomain.entities.produccion.PParteTrabajo;
import com.mydomain.util.dao.DaoException;
import com.mydomain.util.exception.FindException;
public interface ParteTrabajoServiceI<T> {
public T iniciarParteTrabajo(int idMaquina, int idEstacion, int idOperario, int idTrabajo, int idOrden)
throws FindException;
public PParteTrabajo iniciarFinalizarParteTrabajo(int idMaquina, int idEstacion, int idOperario, int idTrabajo,
int idOrden) throws FindException, DaoException;
public T iniciarParteTrabajoMaquinaTrabajoUnico(int idMaquina, int idOperario, int idOrden) throws FindException,
DaoException;
public PParteTrabajo finalizarParteTrabajo(T parteTrabajoIniciado, BigDecimal cantidad) throws DaoException,
FindException;
public List<PParteTrabajo> finalizarPartesTrabajosIniciados(int idMaquina, int idOperario) throws FindException,
DaoException;
public List<T> getPartesTrabajoIniciados(int idMaquina, int idOperario) throws FindException;
public List<T> getPartesTrabajoIniciados(int idMaquina) throws FindException;
public List<T> findAll() throws FindException;
}
and
package com.mydomain.services.produccion;
import com.mydomain.dao.produccion.ParteTrabajoDaoI;
import com.mydomain.entities.produccion.PParteTrabajo;
import com.mydomain.util.dao.DaoException;
import com.mydomain.util.exception.FindException;
#Service("parteTrabajoServicePrueba")
public class ParteTrabajoServiceExample implements
ParteTrabajoServiceI<ParteTrabajoServiceExample.ParteTrabajoIniciado> {
#Autowired
#Qualifier("MiParteTrabajoDao")
private ParteTrabajoDaoI parteTrabajoDaoI;
#Override
public List<ParteTrabajoIniciado> getPartesTrabajoIniciados(final int idMaquina, final int idOperario) {
return null;
}
public class ParteTrabajoIniciado {
private final PParteTrabajo parte;
private ParteTrabajoIniciado(final PParteTrabajo parteTrabajo) {
parte = parteTrabajo;
}
public int getIdOrdenProduccion() {
return parte.getIdOrdenProduccion();
}
}
....
}
and
package com.mydomain.iweb;
#SpringBootApplication
#Configuration
#Import(com.mydomain.services.ServicesBeanConfig.class)
#EnableTransactionManagement
#EnableAutoConfiguration
#PropertySource("file:etc/application.properties")
#EnableJpaRepositories("com.mydomain.repository,com.mydomain.dao")
public class Application {
private static final Logger LOG = LoggerFactory.getLogger(Application.class.getName());
#Value("${spring.datasource.jndi-name}")
private String jndiResourceName;
#Value("${spring.datasource.name}")
private String jdbcName;
#Value("${spring.datasource.driver-class-name}")
private String jdbcDriverClassName;
#Value("${spring.datasource.url}")
private String jdbcUrl;
#Inject
ApplicationContext ctx;
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
.....
}
The value for EnableJpaRepositories is wrong.
The value is an array, so it should be
#EnableJpaRepositories(value ={"com.mydomain.repository","com.mydomain.dao"})
The way you declared it spring would try to scan only one package with the name
"com.mydomain.repository,com.mydomain.dao"
which for sure is not what you want.
You may have missed the bean implementing the ParteTrabajoRepository interface.
com.mydomain.repository.produccion.ParteTrabajoRepository is just an interface but it needs a concrete implementation in order for it to be injected with #Autowired