How to use MyBatis with CDI - cdi

I am writing a web application and I am using MyBatis framework for persistence. I want to use CDI to inject the mappers easily and to manage the transaction declaratively.

MyBatis has official CDI support:
Mapper declaration:
#Mapper
public interface UserMapper {
#Select("SELECT * FROM users WHERE id = #{userId}")
User getUser(#Param("userId") String userId);
}
Mapper Usage:
public class MyService {
#Inject UserMapper userMapper;
public User doSomeStuff(String userId) {
return this.userMapper.getUser(userId);
}
}
More information in docs: http://mybatis.org/cdi/

Related

Can I access the current user in session statically in Quarkus?

I need to do access to the current user (previously set up by a ContainerRequestFilter) in a static way, to avoid the passage of the #Context SecurityContext in every method of every controller.
I want to achieve something that, in Spring, I would do with
SecurityContextHolder.getContext().getAuthentication();
Is there any way to do it, besides using Spring Security in Quarkus?
The solution is to use this dependency
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
Then you can manipulate the instance of SecurityIdentity to "make it static"
#Startup
#ApplicationScoped
public class UserUtilsService {
#Inject
private SecurityIdentity securityIdentity;
private static SecurityIdentity instance;
/**
* Gets the custom user.
*
* #return the custom user
*/
public static CustomUser getCustomUser() {
return (CustomUser) instance.getPrincipal();
}
#PostConstruct
private void setUp() {
instance = this.securityIdentity;
}
}
#StartUp does instantiate the bean on application start (instead of lazily).
You can then access to the Principal statically using UserUtilsService.getCustomUser();

Inject different implementations based on application property in Quarkus

I have a Repository interface that has two implementations. One reads data from a locally stored CSV file while the other reads from an Amazon Dynamo DB. I would like to be able to switch between which implementation I'm using based on an application property or custom build profile. I would normally use a Factory to retrieve the correct class at runtime, but I would like to do this with injection if possible.
I found a similar question using Spring boot but couldn't find an equivalent that would work in Quarkus Spring choose bean implementation at runtime
I also tried implementing a Configuration class similar to what is found in the docs here but again didn't have much luck. https://quarkus.io/guides/cdi-reference#default_beans
It feels like I'm missing something obvious so any pointers would be much appreciated.
Here is a simple example of my classes:
#ApplicationScoped
public class ExampleService {
#Inject
ExampleRepository repository;
public List<Data> retrieveData() {
return repository.retrieveData();
}
}
public interface ExampleRepository {
List<Data> retrieveData();
}
#ApplicationScoped
public class DynamoRepository implements ExampleRepository {
#Override
public List<Data> retrieveData() {
//Get Data from DynamoDb
}
}
#ApplicationScoped
public class CsvRepository implements ExampleRepository {
#Inject
CsvBeanHandler csvBeanHandler;
#Inject
LocalFileReader fileReader;
#Override
public List<Data> retrieveData() {
// Get data from CSV
}
}
I currently also have the following in my application.yml:
com:
example:
application:
storage-type: 'CSV' # OR AMAZON_DYNAMO_DB
It looks like they've added this directly to the documentation:
https://quarkus.io/guides/cdi-reference#declaratively-choose-beans-that-can-be-obtained-by-programmatic-lookup
I feel a bit guilty pasting this much, but it's the SO way.
I can add that it is NOT like a Guice 'binding'; BOTH classes will be instantiated, but only one will be injected. Also unlike Guice, you cannot inject the interface (or I did it wrong) - you have to do what's shown below, with Instance.
Personally I just use constructor injection and then drop the value of the Instance wrapper into a final field, so I'm not crying about the extra step. I do miss the power and explicit bindings possible with Modules ala Guice, but the simplicity here has its own value.
5.16. Declaratively Choose Beans That Can Be Obtained by Programmatic Lookup
It is sometimes useful to narrow down the set of beans that can be
obtained by programmatic lookup via javax.enterprise.inject.Instance.
Typically, a user needs to choose the appropriate implementation of an
interface based on a runtime configuration property.
Imagine that we have two beans implementing the interface
org.acme.Service. You can’t inject the org.acme.Service directly
unless your implementations declare a CDI qualifier. However, you can
inject the Instance instead, then iterate over all
implementations and choose the correct one manually. Alternatively,
you can use the #LookupIfProperty and #LookupUnlessProperty
annotations. #LookupIfProperty indicates that a bean should only be
obtained if a runtime configuration property matches the provided
value. #LookupUnlessProperty, on the other hand, indicates that a bean
should only be obtained if a runtime configuration property does not
match the provided value.
#LookupIfProperty Example
interface Service {
String name();
}
#LookupIfProperty(name = "service.foo.enabled", stringValue = "true")
#ApplicationScoped
class ServiceFoo implements Service {
public String name() {
return "foo";
}
}
#ApplicationScoped
class ServiceBar implements Service {
public String name() {
return "bar";
}
}
#ApplicationScoped
class Client {
#Inject
Instance<Service> service;
void printServiceName() {
// This will print "bar" if the property "service.foo.enabled" is NOT set to "true"
// If "service.foo.enabled" is set to "true" then service.get() would result in an AmbiguousResolutionException
System.out.println(service.get().name());
}
}
If your request is to bind at startup time the right implementation based on a configuration property, I suppose your problem may be resolved used #Produces annotation:
public class ExampleRepositoryFactory {
#Config("storage-type")
String storageType;
#Produces
public ExampleRepository dynamoInstance() {
return storageType == "CSV" ? new CsvRepository() : new DynamoRepository();
}
}

Run Query against multiple namespaces with Spring Data Cassandra

Is there any way in which using Spring Data a query can be executed on all keyspaces in Cassandra?
There are two parts to this answer:
When using Spring Data Cassandra 1.x, you are need to setup individual CassandraTemplate instances for each keyspace you want to use.
With Spring Data Cassandra 2.x, we introduced the SessionFactory interface to control which Session to use. We ship with routing SessionFactory support so you can provide multiple sessions and a discriminator (usually something ThreadLocal-based) to select the appropriate Session.
Some example code for 2.0 would look like:
class MyRoutingSessionFactory extends AbstractRoutingSessionFactory {
ThreadLocal<String> lookupKey = ThreadLocal.withInitial(() -> "default-session");
void setLookupKey(String lookupKey) {
this.lookupKey.set(lookupKey);
}
#Override
protected Object determineCurrentLookupKey() {
return lookupKey.get();
}
}
class MyConfig extends AbstractCassandraConfiguration {
#Bean
#Override
public SessionFactory sessionFactory() {
MyRoutingSessionFactory factory = new MyRoutingSessionFactory();
factory.setDefaultTargetSessionFactory(getRequiredSession());
MapSessionFactoryLookup lookup = new MapSessionFactoryLookup();
Session myOtherSession = …;
lookup.addSessionFactory("default-session", getRequiredSession());
lookup.addSessionFactory("my-other-session", myOtherSession);
factory.setSessionFactoryLookup(lookup);
return factory;
}
// …
}

ServiceStack Access Ioc container within Custom CredentialsAuthProvider

I've extended the CredentialsAuthProvider provided by service-stack to allow me to authenticate against a Active-Directory instance. The AD access logic is encapsulated within a custom class called AdManager (see below)
e.g.:
public class AdCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService,
string userName,
string password)
{
IAdManager manager = new AdManager();
return manager.Authenticate(userName, password);
}
...
Question:
I was hoping I could register the AdManager using service-stacks built-in IoC "Funq.Container" within my extended "AppHostBase" and access it from within my custom CredentialsAuthProvider? I tried registering it but have not found a way of accessing the IoC (or my registered AdManager object) via the service-stack built in framework.
Am I missing something?
Thanks
You can access the IOC from within the AuthProvider with the supplied IServiceBase, e.g:
var addManager = authService.TryResolve<IAdManager>();
Anywhere else you can always resolve dependencies using the Singleton:
var addManager = HostContext.TryResolve<IAdManager>();
Otherwise if you know it's in an ASP.NET Web Host you also access it via your AppHost singleton:
var addManager = AppHostBase.Instance.Resolve<IAdManager>();
Service Stack uses property injection as well. I have used property injection when extending the Service class provided by Service stack.
public class MyService : Service
{
public MyService(IDb db)
{
//db constructor inject
}
public IValidator<MyData> MyDataValidator { get; set; }
public object Get(MyData request)
{
//MyDataValidator is property injected
}
}
I believe the same logic can be applied to the AuthProvider. But I havent tested it.

Servicestack with Autofac not resolving IRequestContext

I am trying to use the Cache facilities of Service Stack. These are accessed through the
RequestContext, which is injected by the IOC in your Service.
This works as expected if you are using the default Funq IOC, it does not work when you hook AutoFac, RequestContext is null and I am not sure how to configure autofac to build it. Any clues here? My AutoFac configuration:
var builder = new ContainerBuilder();
//Now register all dependencies to your custom IoC container
builder.RegisterAssemblyTypes(new[] { typeof(AppHost).Assembly })
.PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies)
.AsImplementedInterfaces()
.SingleInstance();
container.Register<ICacheClient>(new MemoryCacheClient());
IContainerAdapter adapter = new AutofacIocAdapter(builder.Build());
container.Adapter = adapter;
EDIT:
My Service already extends ServiceStack.ServiceInterface.Service:
public class UserDetailsService : ServiceStack.ServiceInterface.Service
which implements IRequiresRequestContext, RequestContext is null. If I remove autofac then it works as expected. With Autofac RequestContext is null
RequestContext is not meant to be injected by an IOC, it's a special property that is set by ServiceStack if your Service requests it by implementing the IRequiresRequestContext interface. E.g.
public class MyClass : IService, IRequiresRequestContext {
//injected by ServiceStack at run-time (per request)
public IRequestContext RequestContext { get; set; }
}
This is the same mechanism how the RequestContext property gets populated in the convenient default Service base class in ServiceStack.

Resources