springboot could not found feignclient - spring-boot

ERROR INFO LIKE BELOW:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field helloAgent in com.example.client.controller.Hello required a bean of
type 'com.example.common.agent.HelloAgent' that could not be found.
Action:
Consider defining a bean of type 'com.example.common.agent.HelloAgent' in
your configuration.
project structure:
module: test-client as feignclient caller.
module: test-server as feignclient interface implementation.
module: test-common put all feignclient together.
test-common:
package com.example.common.agent;
#FeignClient("hello")
public interface HelloAgent {
#GetMapping("/hello")
String hello(#RequestParam String msg);
}
test-server:(works fine)
package com.example.server.controller;
#RestController
public class Hello implements HelloAgent {
#Override
public String hello(#RequestParam String msg) {
System.out.println("get " + msg);
return "Hi " + msg;
}
}
test-client:
package com.example.client.controller;
#RestController
public class Hello {
#Autowired
private HelloAgent helloAgent;
#GetMapping("/test")
public String test() {
System.out.println("go");
String ret = helloAgent.hello("client");
System.out.println("back " + ret);
return ret;
}
}
----------------------------
#EnableEurekaClient
#EnableFeignClients
#SpringBootApplication
#ComponentScan(basePackages = {"com.example.common.agent","com.example.client.controller"})
public class TestClientApplication {
public static void main(String[] args) {
SpringApplication.run(TestClientApplication.class, args);
}
}
Is there anyway to put all feignclient together so that we can manage them gracefully?
Or there is only way to use them redundancy?
THANKS!

Feign doesn't know about #ComponentScan.
Use #EnableFeignClients(basePackages = {"com.example.common.agent","com.example.client.controller"})

Solution using Configuration
In case you use Swagger Codegen, you can use a configuration to bootstrap the apis:
#Configuration
public class ParkingPlusFeignClientConfiguration {
#Autowired
private ParkingPlusProperties properties;
#Bean
public ServicoPagamentoTicket2Api ticketApi() {
ApiClient client = new ApiClient();
// https://stackoverflow.com/questions/42751269/feign-logging-not-working/59651045#59651045
client.getFeignBuilder().logLevel(properties.getClientLogLevel());
client.setBasePath(properties.getHost());
// Generated from swagger: https://demonstracao.parkingplus.com.br/servicos
return client.buildClient(ServicoPagamentoTicket2Api.class);
}
}

Related

Java 8 Optional injection with Sprint Boot 2

Posting here before annoying the Spring Boot team on GitHub! :)
Unless I'm doing something incredibly wrong (and it may very well be), I've noticed a weird pattern when injecting an Optional bean with Spring Boot (2.0.3.RELEASE).
The following works and I do understand why:
#SpringBootApplication
public class OptionalInjection {
public static void main(String[] args) {
ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(OptionalInjection.class, args);
Foo foo = configurableApplicationContext.getBean(Foo.class);
System.out.println(foo.getOptionalString());
}
#Configuration
static class Config {
#Bean
public String optionalString() {
return someMethodThatReturnsAnOptional()
.orElse(null); // I so don't like unwrapping the Optional here!
}
}
#Component
static class Foo {
private final Optional<String> optionalString;
#Autowired
public Foo(Optional<String> optionalString) {
this.optionalString = optionalString;
}
public Optional<String> getOptionalString() {
return optionalString;
}
}
private static Optional<String> someMethodThatReturnsAnOptional() {
return Optional.of("Some string!");
}
}
But what I was actually trying to do is:
#SpringBootApplication
public class OptionalInjection {
// ...
#Configuration
static class Config {
#Bean
public Optional<String> optionalString() {
return someMethodThatReturnsAnOptional(); // no Optional unwrapping!
}
}
// ...
}
Is there a way to make the second option work?
P.S. constructor injection is a must here! :)

How to consume protobuf parameters using Spring REST?

I'm trying to pass a protobuf parameter to a REST endpoint but I get
org.springframework.web.client.HttpServerErrorException: 500 null
each time I try. What I have now is something like this:
#RestController
public class TestTaskEndpoint {
#PostMapping(value = "/testTask", consumes = "application/x-protobuf", produces = "application/x-protobuf")
TestTaskComplete processTestTask(TestTask testTask) {
// TestTask is a generated protobuf class
return generateResult(testTask);
}
}
#Configuration
public class AppConfiguration {
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
#SpringBootApplication
public class JavaConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(JavaConnectorApplication.class, args);
}
}
and my test looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#WebAppConfiguration
public class JavaConnectorApplicationTest {
#Configuration
public static class RestClientConfiguration {
#Bean
RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
return new RestTemplate(Arrays.asList(hmc));
}
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
#Autowired
private RestTemplate restTemplate;
private int port = 8081;
#Test
public void contextLoaded() {
TestTask testTask = generateTestTask();
final String url = "http://127.0.0.1:" + port + "/testTask/";
ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);
// ...
}
}
I'm sure that it is something with the parameters because if I create a variant which does not take a protobuf parameter but returns one it just works fine. I tried debugging the controller code but the execution does not reach the method so the problem is probably somewhere else. How do I correctly parametrize this REST method?
This is my first stack overflow answer but I was a lot to frustred from searching for working examples with protobuf over http and spring.
the answer https://stackoverflow.com/a/44592469/15705964 from Jorge is nearly correct.
Like the comments mention: "This won't work in itself. You need to add a converter somewhere at least."
Do it like this:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Autowired
ProtobufHttpMessageConverter protobufHttpMessageConverter;
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(protobufHttpMessageConverter);
}
}
The ProtobufHttpMessageConverter will do his job automatically and add the object to your controller methode
#RestController
public class ProtobufController {
#PostMapping(consumes = "application/x-protobuf", produces = "application/x-protobuf")
public ResponseEntity<TestMessage.Response> handlePost(#RequestBody TestMessage.Request protobuf) {
TestMessage.Response response = TestMessage.Response.newBuilder().setQuery("This is a protobuf server Response")
.build();
return ResponseEntity.ok(response);
}
Working example with send and reseive with rest take a look: https://github.com/Chriz42/spring-boot_protobuf_example
Here it's the complete answer
#SpringBootApplication
public class JavaConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(JavaConnectorApplication.class, args);
}
}
Then you need to provide the right configuration.
#Configuration
public class AppConfiguration {
//You need to add in this list all the messageConverters you will use
#Bean
RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
return new RestTemplate(Arrays.asList(hmc,smc));
}
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
And finally your RestController.
#RestController
public class TestTaskEndpoint {
#PostMapping(value = "/testTask")
TestTaskComplete processTestTask(#RequestBody TestTask testTask) {
// TestTask is a generated protobuf class
return generateResult(testTask);
}
}
The #RequestBody annotation: The body of the request is passed through an HttpMessageConverter (That you already defined) to resolve the method argument depending on the content type of the request
And your test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class JavaConnectorApplicationTest {
#Autowired
private RestTemplate restTemplate;
private int port = 8081;
#Test
public void contextLoaded() {
TestTask testTask = generateTestTask();
final String url = "http://127.0.0.1:" + port + "/testTask/";
ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);
// Assert.assertEquals("dummyData", customer.getBody().getDummyData());
}
}

How to create a mocked (by jmockit) spring bean?

I am new to jmockit and would like to mock a bean inside my Java based Spring Application Configuration. I thought (better hoped) it would go like this:
#Configuration
public class MyApplicationConfig {
#Bean // this bean should be a mock
SomeService getSomeService() {
return new MockUp<SomeService>() {#Mock String someMethod() { return ""; }}.getMockInstance();
}
#Bean // some other bean that depends on the mocked service bean
MyApplication getMyApplication(SomeService someService) {
....
}
}
But unfortunatly this fails with "Invalid place to apply a mock-up".
I wonder if I can generate jmockit mocks inside Spring Configuration classes at all. I need the bean because it is referenced by other beans and the whole Spring Context initialization fails if I do not provide the mock as a Spring bean.
Thanks for any help.
Just use your regular Spring configuration. In a test class, declare the type to be mocked with #Capturing. It will mock whatever the implementation class that Spring used.
Edit: added full example code below.
import javax.inject.*;
public final class MyApplication {
private final String name;
#Inject private SomeService someService;
public MyApplication(String name) { this.name = name; }
public String doSomething() {
String something = someService.doSomething();
return name + ' ' + something;
}
}
public final class SomeService {
public String getName() { return null; }
public String doSomething() { throw new RuntimeException(); }
}
import org.springframework.context.annotation.*;
#Configuration
public class MyRealApplicationConfig {
#Bean
SomeService getSomeService() { return new SomeService(); }
#Bean
MyApplication getMyApplication(SomeService someService) {
String someName = someService.getName();
return new MyApplication(someName);
}
}
import javax.inject.*;
import org.junit.*;
import org.junit.runner.*;
import static org.junit.Assert.*;
import mockit.*;
import org.springframework.test.context.*;
import org.springframework.test.context.junit4.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyRealApplicationConfig.class)
public final class MyApplicationSpringTest {
#Inject MyApplication myApplication;
#Mocked SomeService mockService;
#BeforeClass // runs before Spring configuration
public static void setUpMocksForSpringConfiguration() {
new MockUp<SomeService>() {
#Mock String getName() { return "one"; }
};
}
#Test
public void doSomethingUsingMockedService() {
new Expectations() {{ mockService.doSomething(); result = "two"; }};
String result = myApplication.doSomething();
assertEquals("one two", result);
}
}
import org.junit.*;
import static org.junit.Assert.*;
import mockit.*;
// A simpler version of the test; no Spring.
public final class MyApplicationTest {
#Tested MyApplication myApplication;
#Injectable String name = "one";
#Injectable SomeService mockService;
#Test
public void doSomethingUsingMockedService() {
new Expectations() {{ mockService.doSomething(); result = "two"; }};
String result = myApplication.doSomething();
assertEquals("one two", result);
}
}
Spring-ReInject is designed to replace beans with mocks.

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.

Arquillian and ejb mocking - legacy application

i'm working on legacy project (jee 5, jboss 4.2.3) and i need to write integration tests for this app. I was able to integrate arquillian remote module and run simple tests. But now i would like to mock some services in my ejb using mockito.
Example :
some ejb
#Local
public interface DummyService {
String welcomMessage();
}
#Stateless
#LocalBinding(jndiBinding = "ejb/DummyServiceBean/local")
public class DummyServiceBean implements DummyService {
#EJB(mappedName = "ejb/DummyServiceBean2/local")
private DummyService2 service;
#Override
public String welcomMessage() {
return "world!!!!" + " " + service.getSomething();
}
}
#Local
public interface DummyService2 {
String getSomething();
}
#Stateless
#LocalBinding(jndiBinding = "ejb/DummyServiceBean2/local")
public class DummyServiceBean2 implements DummyService2 {
#Override
public String getSomething() {
return "sth";
}
}
test class
#RunWith(Arquillian.class)
public class DummyServiceTest {
#EJB(mappedName = "ejb/DummyServiceBean/local")
private DummyService service;
#Mock
private DummyService2 service2;
#Deployment
public static Archive<?> createDeployment() {
final JavaArchive javaArchive = ShrinkWrap.create(JavaArchive.class, "test.jar")
.addClasses(DummyService.class, DummyServiceBean.class,
DummyService2.class, DummyServiceBean2.class,
DummyServiceTest.class, InjectMocks.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
return ShrinkWrap.create(EnterpriseArchive.class, "test.ear")
.setApplicationXML(new File("application.xml"))
.addAsLibraries( // add maven resolve artifacts to the deployment
DependencyResolvers.use(MavenDependencyResolver.class)
.loadMetadataFromPom("pom.xml")
.artifact("org.mockito:mockito-all:1.9.5")
.resolveAs(GenericArchive.class))
.addAsModule(javaArchive);
}
#Before
public void setupMock() {
when(service2.getSomething()).thenReturn("qwerty");
}
#Test
public void should_assert_a_behaviour() {
System.out.println("Hello " + service.welcomMessage());
}
}
I can do this by not adding DummyServiceBean2.class into archive and by creating in test directory something like :
#Stateless
#LocalBinding(jndiBinding = "ejb/DummyServiceBean2/local")
public class MockDummyServiceBean2 implements DummyService2 {
#Override
public String getSomething() {
return "mock sth";
}
}
but this is bad practice. I got the idea to swap during runtime DummyServiceBean2 proxy reference using reflection in DummyServiceBean class for a new one with InvocationHandler which use mock inside his invoke method but it ended up on an exception
IllegalArgumentException: Can not set com.example.DummyService2 field com.example.DummyServiceBean.service to com.sun.proxy.$Proxy71
Any ideas how can i swap/replace DummyServiceBean2 proxy for new one or how can i replace invocation handler in existing one ?

Resources