Reference to method is ambiguous method reference vs lambda - java-8

I have following classes
interface 1
package test;
public interface TODO {
boolean test();
}
interface 2
package test;
#FunctionalInterface
public interface FuncN {
State zip(State ...states);
}
class 1
package test;
public class Test {
public static Test define(FuncN zipperFunc,TODO... tasks) {
return null;
}
public static Test define(TODO... tasks) {
return null;
}
}
class 2
package test;
public class State {
public static State mergeStates(State ...states) {
return null;
}
}
main class
package test;
public class Main {
public static void main(String[] args) {
Test.define(State::mergeStates,()->true);
}
}
The class main doesn't compile, throws error
reference to define is ambiguous
Test.define(State::mergeStates,()->true);
^
both method define(FuncN,TODO...) in Test and method define(TODO...) in Test match
Class below does compile:
package test;
public class Main {
public static void main(String[] args) {
Test.define(states->State.mergeStates(states),()->true);
}
}
However i don't see any ambiguity. The signatures of FuncN and TODO are completely different, i don't think compiler should mistake them for one another.
Correct me if i am wrong.
P.S. Error is not reproducible using eclipse, so i would recommend creating a folder test creating all java files in that and run javac test/Main.java

It will compile if you cast the method reference call to FincN. there are two overload methods in Test class call 'define' so compiler confuse to select which one. so try to use as following.
public static void main(String[] args){
Test.define((FuncN) State::mergeStates,()->true);
}

Related

How to do integration tests with ClasspathBeanDefinitionScanner in main class springboot

here's the test I created with JPA
import static org.assertj.core.api.Assertions.assertThat;
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#ExtendWith(SpringExtension.class)
#DataJpaTest
public class IntegrationTest {
#Autowired
private JpaUserRepository jpaUser;
#Test
#DisplayName("Test JPA")
void given123Password_whenPasswordIsNotValid_thenIsFalse() {
Boolean teste = this.jpaUser.existsById("Bruno");
assertThat(teste).isEqualTo(true);
}
}
here`s my main class
#SpringBootApplication
public class CleanArchitectureApplication {
public static void main(String[] args) {
SpringApplication.run(CleanArchitectureApplication.class);
}
}
Success case [https://i.stack.imgur.com/APbBu.png][1]
The problem starts when I add a classPathBeanScanner in my main class
#SpringBootApplication
public class CleanArchitectureApplication {
public static void main(String[] args) {
SpringApplication.run(CleanArchitectureApplication.class);
}
#Bean
BeanFactoryPostProcessor beanFactoryPostProcessor(ApplicationContext beanRegistry) {
return beanFactory -> {
genericApplicationContext((BeanDefinitionRegistry) ((AnnotationConfigServletWebServerApplicationContext) beanRegistry).getBeanFactory());
};
}
void genericApplicationContext(BeanDefinitionRegistry beanRegistry) {
ClassPathBeanDefinitionScanner beanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanRegistry);
beanDefinitionScanner.addIncludeFilter(removeModelAndEntitiesFilter());
beanDefinitionScanner.scan("com.baeldung.pattern.cleanarchitecture");
}
static TypeFilter removeModelAndEntitiesFilter() {
return (MetadataReader mr, MetadataReaderFactory mrf) -> !mr.getClassMetadata()
.getClassName()
.endsWith("Model");
}
}
Error case [https://i.stack.imgur.com/IL0Qf.png][2]
I'm trying to implement clean architecture and abstracting main class in spring boot from this article I'm reading[https://www.baeldung.com/spring-boot-clean-architecture](https://www.stackoverflow.com/). but the problem starts when I try to do the integration test and it conflicts contexts and beans after adding the classPathBeanDefinitionScanner.
I've tried setting up different test contexts and different beans.
[1]: https://i.stack.imgur.com/APbBu.png
[2]: https://i.stack.imgur.com/IL0Qf.png

spring: #bean CommandlineRunner. How it returns an object of type CommandlineRunner

I have seen in many places
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner demo(UserRepository repo) {
return (args) -> {
};
}
}
how does
#Bean
public CommandLineRunner demo(UserRepository repo) {
return (args) -> {
};
}
return an object of type CommandLineRunner
it return a function
(args) -> {
};
I am not able to understand the syntax also.
Can someone help me to understand
CommandLineRunner is an interface used to indicate that a bean should run when it is contained within a SpringApplication. A Spring Boot application can have multiple beans implementing CommandLineRunner. These can be ordered with #Order.
It has one abstract method :
void run(String... args) throws Exception
Consider below example:
#Component
public class MyCommandLineRunner implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(MyCommandLineRunner.class);
#Override
public void run(String... args) throws Exception {
logger.info("Loading data..." + args.toString());
}
}
Since CommandLineRunner contains only only abstract method which return nothing so it automatically becomes the functional interface i.e. we can write lambda expression for it.
Above class can be written as :
(args) -> {
logger.info("Loading data..." + args.toString())
};
Coming to Your example :
#Bean
public CommandLineRunner demo(String... args) {
return (args) -> {
};
}
You are expecting to register a bean in Spring Container which implements CommandLineRunner interface so it can converted to lambda expression.
(args) -> {};
Hope this would clarify it enough.
CommandLineRunner is a functional interface with one method that return void.
That is why when you write: { }; everything is OK.
you should check functional interfaces of Java,
https://www.geeksforgeeks.org/functional-interfaces-java/
In syntheses,
A functional interface is a Java interface with only one abstract method (i.e., a method which has no instructions, only a name).
Functional interfaces are used together with lambda functions.
Suppose we have a functional interface
public interface JustAFunctionalInterface {
void execute() {};
}
Notice we have only an abstract method, which does not do anything (no instructions).
This functional interface can be implemented like in your code above:
public class Main {
public static void main(String[] args) {
JustAFunctionalInterface variable = justAFunctionalInterface();
variable.execute() // This will print "Hi"
};
public static JustAFunctionalInterface justAFunctionalInterface() {
return (args) -> {System.out.println('Hi')}
}; // This chunk of code says that this method will return an interface of type
// JustAFunctionalInterface already implemented, where the abstract method "execute" is assigned the lambda function returned in here
}

Dropwizard: integration of Google Guice

I try to use dependency injection in DropWizard with Google Guice but I have a lot of problems. So I programmed a simple code like below to find the main problem. The errors are in the class Test, line :testservice.Result (10,10,10).
- Syntax error on token "(", { expected after this token
- Syntax error on tokens, ConstructorHeaderName expected
instead
- Syntax error on token "Result", invalid AnnotationName
why I can't use the object testservice ?
Thanks for your help.
package dropwizard.GoogleGuiiice;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
public class GoogleGuiiiceApplication extends Application<GoogleGuiiiceConfiguration> {
public static void main(final String[] args) throws Exception {
new GoogleGuiiiceApplication().run(args);
}
#Override
public String getName() {
return "GoogleGuiiice";
}
#Override
public void initialize(final Bootstrap<GoogleGuiiiceConfiguration> bootstrap) {
// TODO: application initialization
}
#Override
public void run(final GoogleGuiiiceConfiguration configuration,
final Environment environment) {
// TODO: implement application
environment.jersey().register(new Test ());
}
}
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Test {
Injector guice=Guice.createInjector(new OperationModule());
TestService testservice=guice.getInstance(TestService.class);
testservice.Result (10,10,10);
}
public interface Operation {
int getResult(int a, int b);
}
public class Somme implements Operation{
#Override
public int getResult(int a, int b){
return a+b;
}
}
public class OperationModule extends com.google.inject.AbstractModule{
#Override
protected void configure(){
bind(Operation.class).to(Somme.class);
}
}
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import com.google.inject.Inject;
public class TestService {
#Inject
Operation Op;
#GET
#Path("{a}/{b}")
public int Result (int c, #PathParam(value="a")int a, #PathParam(value="b")int b){
int SommeFinale=c + Op.getResult(a,b);
return SommeFinale;
}
}
It is not clear to me what you are actually attempting to do here but to answer your question from a purely Java perspective the syntax error is simply because you are not allowed to execute arbitrary statements at that point in your code.
If you really do wish to execute that statement at that point then you either need to wrap it in curly braces so that it is in an initializer block but this would likely be pointless given the implementation as the result is thrown away
{
testService.Result(10,10,10);
}
or you need to assign the result to a field
int useMe = testService.Result(10,10,10);
Other options are that you could execute the statement in a constructor or method of the Test class.
I hope this tutorial can help.
Dropwizard and Guice Integration

Spring-Boot Access object created in main from RequestMapping

I am using spring-boot for implementing a REST server. Inside a function for request mapping, I have to create an object which is heavyweight, so for every REST call I have do it and it is slowing things down. Is it possible to create the object in main and access from the function?
#SpringBootApplication
public class MyClass{
public static void main(String[] args) {
/* I want to initialize the object here */
SpringApplication.run(MyClass.class, args);
}
}
#RestController
public class MyController {
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
/* I want to use the object here */
}
You can create a bean in MyClass and then consume that bean in MyController. Spring will only create a single instance of the bean so you'll avoid the cost of creating it multiple times. Something like this:
#SpringBootApplication
public class MyClass {
public static void main(String[] args) {
SpringApplication.run(MyClass.class, args);
}
#Bean
public Heavyweight heavyweight() {
// Initialize and return heavyweight object here
}
}
#RestController
public class MyController {
private final Heavyweight heavyweight;
#Autowired
public MyController(Heavyweight heavyweight) {
this.heavyweight = heavyweight;
}
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
// Use heavyweight here
this.heavyweight.foo();
// ...
return users;
}
}
I think You can use #Service for this approach. Service class is Singleton so if You create object inside it on startup application then You can use it requests in Your controllers class.
Example service:
#Service
public class MyService{
private MyLargeObject largeObject;
public MyLargeObject set(MyLargeObject largeObject){
this.largeObject = largeObject;
}
public MyLargeObject get(){
return largeObject;
}
}
Example controller:
#RestController
public class MyController{
#Inject
private MyService myService;
#RequestMapping("/go/to/user/summary")
public Users[] getUsers(#RequestParam(value="length", defaultValue="10") int length) {
MyLargeObject o = myService.get();
}
}
EDIT1:
If You want init Your largeObject directly in service You can use #PostConstruct annotation. For example:
#PostConstruct
public void init() {
// initialization Your object here
}

Spring 4 with caching and generic type autowiring

I'm using the latest version of Spring and I'm getting startup errors when I attempt to inject the same generic type twice and the generic type's implementation uses caching.
Below is the simplest example I can create to duplicate the error.
// build.gradle dependencies
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
}
// MyApplication.java
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
// HomeController.java
#RestController
#RequestMapping(value = "/home")
public class HomeController {
#Autowired
public HomeController(
GenericService<String> s1,
GenericService<String> s2, // <-- Notice GenericService<String> twice
GenericService<Integer> s3
) {}
}
// GenericService.java
public interface GenericService<T> {
public T aMethod();
}
// IntegerService.java
#Service
public class IntegerService implements GenericService<Integer> {
#Override
#Cacheable("IntegerMethod")
public Integer aMethod() {
return null;
}
}
// StringService.java
#Service
public class StringService implements GenericService<String> {
#Override
#Cacheable("StringMethod")
public String aMethod() {
return null;
}
}
This compiles fine, but when I run the application, I get the following error:
No qualifying bean of type [demo.GenericService] is defined: expected single matching bean but found 2: integerService,stringService
I have not tried using qualifiers yet, but I'm guessing that would be a work-around. I will try it after posting this. Ideally, I'd like the autowiring of generics and caching to integrate out-of-box. Am I doing something wrong, or is there anything I can do to get it working?
Thank you!
If you would like to not have to use the #Qualifier in the constructor and still use the interfaces, you could just add a value to the service declarations.
#Service(value = "integerService")
public class IntegerService implements GenericService<Integer> {
#Override
#Cacheable("IntegerMethod")
public Integer aMethod() {
return 42;
}
}
#Service(value = "stringService")
public class StringService implements GenericService<String> {
#Override
#Cacheable("StringMethod")
public Integer aMethod() {
return 42;
}
}
Just to be sure, I created a project with Spring-Boot, compiled and ran it. So the above should work. It's basically the same as what you're already doing, but with less typing.
My previous answer (before modifying) was to do something like this:
// HomeController.java
#RestController
#RequestMapping(value = "/home")
public class HomeController {
#Autowired
public HomeController(
StringService s1,
StringService s2,
IntegerService s3
) {}
}
But you would have to not implement the interfaces to make this work.

Resources