How to make multiple FeignClient-s to use same serviceId/name? - spring

assume 2 endpoints:
#RequestMapping("/ep1")
interface Endpoint1 {
#GetMapping("/echo")
String echo();
}
#RequestMapping("/ep2")
interface Endpoint2 {
#GetMapping("/echo")
String echo();
}
On backend side are both running in same server which is registered as serviceId="MY-SERVER" in Eureka or Consul or ...
#RestController
public class Endpoint1Controller implements Endpoint1 {
public String echo() {
return "echo from Endpoint1"
}
}
#RestController
public class Endpoint2Controller implements Endpoint2 {
public String echo() {
return "echo from Endpoint2"
}
}
now my 2 FeignClients have to share same name/serviceId to be able to discover the service in Eureka/Consul but serviceId should be unique per feign client! ...how to deal with this?
#FeignClient("MY-SERVER")
public interface Endpoint1Client extends Endpoint1 {
}
#FeignClient("MY-SERVER")
public interface Endpoint2Client extends Endpoint2 {
}
The bean 'MY-SERVER.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.
Please consider there could be much more endpoints on single server/backend before advicing me to join it into single interface...

oooh, I see now! What should be unique is contextId not value/name
#FeignClient(name="MY-SERVER", contextId = "THIS-SHOULD-BE-UNIQUE")

Related

Combine two API from elasticsearch and PostgreSQL in Spring Boot

I have API
using elasticsearchrepository
#Autowired
private SinhvienesRepo sinhvienesrepo;
using PostgreSQL jparepository
#Autowired
private SinhvienRepo sinhvienrepo;
#GetMapping("/sinhvienes")
Iterable<Sinhvienes> Sinhvienes() {
return sinhvienesrepo.findAll();
}
#GetMapping("/sinhviens")
List<Sinhvien> Sinhvien() {
return sinhvienrepo.findAll();
}
it work well
but now I want to combine them when I request the parameter isEs == true I use this API of elasticsearch
and else I want to use API of PostgreSQL
You can use params field of the #GetMapping annotation:
#RestController
public class TestController {
#GetMapping(value = "/sinhvienes", params = "isEs=true")
public String sinhvienEs() {
return "ES";
}
#GetMapping("/sinhvienes")
public String sinhvien() {
return "NO ES";
}
}

Querying mongodb collection SpringWebFlux with reactivemongodb

I am developing simple spring webflux demo application with reactive mongodb and i want to read all data of Employee by name except containing name field "joe","Sara","JOE","SARA" and i have following code like:
//repository interface
public interface EmployeeRepository extends ReactiveMongoRepository<Employee, String>{
Flux<Employee> findAllByName(String name);
}
//Service class
public class EmplyeeService
{
private EmployeeRepository employeeRepository;
public Flux<Employee> findAllByOrganizationName(String name)
{
return employeeRepository.findAllByName(name);
}
public Flux<String> getAllNameExceptSome(String name)
{
Employee emp1=new Employee();
List<Flux<Employee>> emp=Arrays.asList(employeeRepository.findAllByName(name));
Flux<Flux<Employee>> emp2=Flux.fromIterable(emp)
.filter(name->name.equalsIgnoreCase("joe"));
return emp2;
}
}
First of all, unless some particular situations, you should avoid these data structures:
List<Flux<Employee>>
Flux<Flux<Employee>>
However you are not leveraging Spring Data. You can achieve you result simply changing your repository to:
public interface EmployeeRepository extends ReactiveMongoRepository<Employee, String> {
// this find all Employee except those matching names provided as param
Flux<Employee> findAllByNameNotIn(List<String> nameList);
// this find all Employee matching names provided as param
Flux<Employee> findAllByNameIn(List<String> nameList);
}
Invoking this method you will obtain the list of Employee already filtered by name.

Spring - Access a Service interface programmatically

i have several interfaces which extend a single interface.
I need to add, during a #PostCostruct method, these interfaces to a Map.
The problem is that i need to retrieve the #Service class name from the DB and i don't know ho to put the interface in the map...
I'll try to explain it better
I have a general service interface
public interface IVehicleServiceGeneral{
//methods...
}
then i have several interfaces which extend the general one.
public interface IService1 extends IVehicleServiceGeneral{
}
public interface IService2 extends IVehicleServiceGeneral{
}
the concrete implementations of these classes are annotated with #Service("service1Name"), #Service("service2Name") and so on...
Then from the DB i retrieve my Suppliers
public class Supplier {
private long id;
private String serviceName;
//getters and setters
}
Finally i need to create the map, because i need to access the implementations at runtime based on the Supplier, i created a ContextAware class to get my beans by name, but the interfaces are not beans... I also tried to put the #Qualifier on the interface, but obviously it does not work... How can I put the interface in the map?
#PostConstruct
private void createServiceMap(){
serviceMap = new HashMap<OBUSupplier, IVehicleServiceGeneral>();
List<Supplier> suppliers = supplierService.findAll();
for(Supplier s : suppliers) {
serviceMap.put(s, contextAware.getBean(s.getServiceName()));
}
}
You can create IVehicleServiceGeneral instance map like this:
class SomeClass {
Map vehicleServiceGeneralInstanceMap = new HashMap();
SomeClass(Set<IVehicleServiceGeneral> instances) {
instances.forEach(i -> vehicleServiceGeneralInstanceMap.put(i.getServiceName(), i));
}
private void createServiceMap() {
Map serviceMap = new HashMap<OBUSupplier, IVehicleServiceGeneral>();
List<Supplier> suppliers = supplierService.findAll();
for(Supplier s : suppliers) {
serviceMap.put(s, vehicleServiceGeneralInstanceMap.get(s.getServiceName()));
}
}
The only thing you require is IVehicleServiceGeneral#getServiceName which your Service1, 2 need to override with proper names that present in DB.

Proxy design pattern with IoC

I am trying to implement proxy design pattern for caching services as below.
public interface IProductService
{
int ProcessOrder(int orderId);
}
public class ProductService : IProductService
{
public int ProcessOrder(int orderId)
{
// implementation
}
}
public class CachedProductService : IProductService
{
private IProductService _realService;
public CachedProductService(IProductService realService)
{
_realService = realService;
}
public int ProcessOrder(int orderId)
{
if (exists-in-cache)
return from cache
else
return _realService.ProcessOrder(orderId);
}
}
How do I to use IoC container (Unity/Autofac) to create real service and cached service objects as I can register IProductService to ProductService or CachedProductService but CachedProductService in turn requires a IProductService object (ProductService) during creation.
I am trying to arrive at something like this:
The application will target IProductService and request IoC container for an instance and depending on the configuration of the application (if cache is enabled/disabled), the application will be provided with ProductService or CachedProductService instance.
Any ideas? Thanks.
Without a container your graph would look like this:
new CachedProductService(
new ProductService());
Here's an example using Simple Injector:
container.Register<IProductService, ProductService>();
// Add caching conditionally based on a config switch
if (ConfigurationManager.AppSettings["usecaching"] == "true")
container.RegisterDecorator<IProductService, CachedProductService>();

Dynamically fire CDI event with qualifier with members

I'm trying to use CDI events in my backend services, on JBoss AS6 - ideally with maximum code reuse.
I can see from the docs I can cut down on the qualifier annotation classes I have to create by using a qualifier with members e.g.
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface Type {
TypeEnum value();
}
I can observe this with
public void onTypeAEvent(#Observes #Type(TypeEnum.TYPEA) String eventMsg) {...}
So far, so good. However, to further cut down on the number of classes needed, I want to have one EventFirer class, where the qualifier of the event thrown is dynamic. Not a problem with qualifiers without members:
public class DynamicEventFirer {
#Inject #Any private Event<String> event;
public void fireEvent(AnnotationLiteral<?> eventQualifier){
event.select(eventQualifier).fire("FIRED");
}
}
then called like
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {});
But what about when the qualifier should have members? Looking at the code for AnnotationLiteral, it's certainly setup for members, and the class element comment has the example:
new PayByQualifier() { public PaymentMethod value() { return CHEQUE; } }
This makes sense to me - you're overriding the value() method of the annotation interface. However, when I tried this myself:
dynamicEventFirer.fireEvent(new AnnotationLiteral<Type>() {
public TypeEnum value() {
return TypeEnum.TYPEA;
}
});
I receive the exception
java.lang.RuntimeException: class uk.co.jam.concept.events.MemberQualifierEventManager$1 does not implement the annotation type with members uk.co.jam.concept.events.Type
at javax.enterprise.util.AnnotationLiteral.getMembers(AnnotationLiteral.java:69)
at javax.enterprise.util.AnnotationLiteral.hashCode(AnnotationLiteral.java:281)
at java.util.HashMap.getEntry(HashMap.java:344)
at java.util.HashMap.containsKey(HashMap.java:335)
at java.util.HashSet.contains(HashSet.java:184)
at org.jboss.weld.util.Beans.mergeInQualifiers(Beans.java:939)
at org.jboss.weld.bean.builtin.FacadeInjectionPoint.<init>(FacadeInjectionPoint.java:29)
at org.jboss.weld.event.EventImpl.selectEvent(EventImpl.java:96)
at org.jboss.weld.event.EventImpl.select(EventImpl.java:80)
at uk.co.jam.concept.events.DynamicEventFirer.fireEvent(DynamicEventFirer.java:20)
Can anyone see what I'm doing wrong? MemberQualifierEventManager is an ApplicationScoped bean which calls on DynamicEventFirer to fire the event.
Thanks,
Ben
There's a slightly cleaner way to do it based on your post:
public class TypeQualifier extends AnnotationLiteral<Type> implements Type{
private TypeEnum type;
public TypeQualifier(TypeEnum t) {
this.type = t;
}
public TypeEnum value() {
return type;
}
}
then just fire like this:
dynamicEventFirer.fireEvent(new TypeQualifier(TypeEnum.TYPEA));
You need to declare an abstract TypeQualifier that extends AnnotationLiteral and implements Type
abstract class TypeQualifier extends AnnotationLiteral<Type> implements Type{}
and use it like this
dynamicEventFirer.fireEvent(new TypeQualifier() {
public TypeEnum value() {
return TypeEnum.TYPEA;
}
});
and later if you want to fire an event with TypeEnum.TYPEB
dynamicEventFirer.fireEvent(new TypeQualifier() {
public TypeEnum value() {
return TypeEnum.TYPEB;
}
});

Resources