Using and extending JOOQ generated DAOs with injected DataSource? - datasource

I'm new to JOOQ... The following code seems to work in WildFly 22 but I'm not sure if that is the best way to do things. What is the preferred way to inject WF DataSource to JOOQ DAOs (my extended ones)? Is there a way to avoid doing the ".get()." in the service below and just leave #Resource(...) etc. connection related for the MyCompanyDAO to handle internally?
In other words: companyDAO.get().fetchOneById(id) vs. companyDAO.fetchOneById(id)
#Stateless
public class CompanyService extends DefaultCompanyService {
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.get().fetchOneById(id);
}
}
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
private MyConnectionProvider cp;
public CompanyDAO get() { // since cannot use #Resource in dao constructor
this.configuration().set(cp).set(SQLDialect.POSTGRES);
return this;
}
// custom code here
}
public class CompanyDao extends DAOImpl<CompanyRecord, tables.pojos.Company, Integer> {
// jooq generated code here
}
#Stateless
#LocalBean
public class MyConnectionProvider implements ConnectionProvider {
#Resource(lookup = "java:/MyDS")
private DataSource dataSource;
#Override
public Connection acquire() throws DataAccessException {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new DataAccessException("Could not acquire connection.", e);
}
}
#Override
public void release(Connection connection) throws DataAccessException {
try {
connection.close();
} catch (SQLException e) {
throw new DataAccessException("Could not release connection.", e);
}
}
}

Put initialization logic of MyCompanyDAO inside a #PostConstruct method.
#PostConstruct
public void init() {
this.configuration().set(cp).set(SQLDialect.POSTGRES);
}
This way, you don't need to call get:
#Inject
private MyCompanyDAO companyDAO;
public Company find(Integer id) {
return companyDAO.fetchOneById(id);
}

How about using constructor injection instead? The generated DAO classes offer a constructor that accepts a Configuration precisely for that:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (Configuration configuration) {
super(configuration);
}
}
If for some reason you cannot inject the entire configuration (which I'd recommend), you could still inject the ConnectionProvider:
#Stateless
public class MyCompanyDAO extends CompanyDao {
#Inject
public MyCompanyDAO (MyConnectionProvider cp) {
super(DSL.using(cp, SQLDialect.POSTGRES));
}
}

Related

How do you adjust json config in Quarkus?

I am attempting to add a mixin to the Jackson's ObjectMapper in a Quarkus project. I have some code that looks likes this:
#Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
this.mapper = createObjectMapper();
}
#Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(MyModel.class, MyMixin.class);
return mapper;
}
}
This code worked perfectly in a Thorntail project I had. For some reason, Quarkus isn't picking this up, and the object mapper is not affected. Is there something different I have to do with the Quarkus CDI?
Updates
Apparently I was a little confused about the implementation. I should be using the Json-B api. I figured out how to change the configuration for Json-B and posted it below.
Instead of providing an ObjectMapper, you can provide a JsonbConfig so that you can customize serialization/deserialization.
Here is what I ended up using:
#Provider
public class JsonConfig implements ContextResolver<Jsonb> {
#Override
public Jsonb getContext(Class type) {
JsonbConfig config = new JsonbConfig();
config.withPropertyVisibilityStrategy(new IgnoreMethods());
return JsonbBuilder.create(config);
}
}
class IgnoreMethods implements PropertyVisibilityStrategy {
#Override
public boolean isVisible(Field field) {
return true;
}
#Override
public boolean isVisible(Method method) {
return false;
}
}
This allows you to customize your JsonbConfig. Here, mine specifically prevents access of methods for serialization/deserialization. On Quarkus with Panache, this prevents isPersistent from appearing in your JSON output.
In addition to the correct answer of #jsolum, here is a working provider which uses the fasterxml-annotations to check visibility of fields and methods:
#Provider
public class JsonConfig implements ContextResolver<Jsonb> {
#Override
public Jsonb getContext(Class aClass) {
JsonbConfig config = new JsonbConfig();
config.withPropertyVisibilityStrategy(new PropertyVisibilityStrategy() {
#Override
public boolean isVisible(Field field) {
JsonIgnore annotation = field.getAnnotation(JsonIgnore.class);
return annotation == null || !annotation.value();
}
#Override
public boolean isVisible(Method method) {
JsonIgnore annotation = method.getAnnotation(JsonIgnore.class);
return annotation == null || !annotation.value();
}
});
return JsonbBuilder.create(config);
}
}
JsonbConfig in Quarkus can be customized providing an ApplicationScoped instance of JsonbConfigCustomizer (taking #jsolum's answer into account):
#ApplicationScoped
public class JsonbFormattingConfig implements JsonbConfigCustomizer {
#Override
public void customize(JsonbConfig jsonbConfig) {
jsonbConfig.withPropertyVisibilityStrategy(new IgnoreMethods());
}
}
class IgnoreMethods implements PropertyVisibilityStrategy {
#Override
public boolean isVisible(Field field) {
return true;
}
#Override
public boolean isVisible(Method method) {
return false;
}
}
Source: https://quarkus.io/guides/rest-json#json-b

How to mock protected final method of base class using jmockit

public class Dao1 extends GenericDao{
}
public class Dao2 extends Dao1{
}
public class GenericDao(){
protected final Session getCurrentSession() {
LOG.debug("getting current Session");
return sessionFactory.getCurrentSession();
}
}
I am testing methods in Dao2 and wants to mock getCurrentSession method from GenericDao.
I tried to mock it using
new MockUp<GenericDao>() {
#Mock
protected Session getCurrentSession() {
return session;
}
};
}
I am getting following exception at line new MockUp<GenericDao>():
java.lang.NoSuchMethodError: mockit.internal.startup.AgentLoader: method <init>()V not found
at mockit.internal.startup.Startup.verifyInitialization(Startup.java:172)
at mockit.MockUp.<clinit>(MockUp.java:94)

Constructor parameter for injected class

Let's say I would like to inject an implementation of this interface:
interface IService { ... }
implemented as:
class MyService : IService
{
public MyService(string s) { }
}
in an instance of this class:
class Target
{
[Inject]
public IService { private get; set; }
}
I do the injection by calling kernel.Inject(new Target()), but what if I would like to specify the parameter s of the constructor depending on some context when calling Inject?
Is there a way to achieve such context-dependant service initialization at injection?
Thanks!
In most cases you should not use Field Injection, it should be
used only in rare cases of circular dependencies.
You should only use the kernel once at the start of your
application and never again.
Example Code:
interface IService { ... }
class Service : IService
{
public Service(string s) { ... }
}
interface ITarget { ... }
class Target : ITarget
{
private IService _service;
public Target(IServiceFactory serviceFactory, string s)
{
_service = serviceFactory.Create(s);
}
}
interface ITargetFactory
{
ITarget Create(string s);
}
interface IServiceFactory
{
IService Create(string s);
}
class NinjectBindModule : NinjectModule
{
public NinjectBindModule()
{
Bind<ITarget>().To<Target>();
Bind<IService>().To<Service>();
Bind<ITargetFactory>().ToFactory().InSingletonScope();
Bind<IServiceFactory>().ToFactory().InSingletonScope();
}
}
Usage:
public class Program
{
public static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new NinjectBindModule());
var targetFactory = kernel.Get<ITargetFactory>();
var target = targetFactory.Create("myString");
target.DoStuff();
}
}
Simply done using parameters...
kernel.Inject(new Target(), new ConstructorArgument("s", "someString", true));

Is it possible to use one generic/abstract service in ServiceStack?

I am developing a (hopefully) RESTful API using ServiceStack.
I noticed that most of my services look the same, for example, a GET method will look something like this:
try
{
Validate();
GetData();
return Response();
}
catch (Exception)
{
//TODO: Log the exception
throw; //rethrow
}
lets say I got 20 resources, 20 request DTOs, so I got about 20 services of the same template more or less...
I tried to make a generic or abstract Service so I can create inheriting services which just implement the relevant behavior but I got stuck because the request DTOs weren't as needed for serialization.
Is there any way to do it?
EDIT:
an Example for what I'm trying to do:
public abstract class MyService<TResponse,TRequest> : Service
{
protected abstract TResponse InnerGet();
protected abstract void InnerDelete();
public TResponse Get(TRequest request)
{
//General Code Here.
TResponse response = InnerGet();
//General Code Here.
return response;
}
public void Delete(TRequest request)
{
//General Code Here.
InnerDelete();
//General Code Here.
}
}
public class AccountService : MyService<Accounts, Account>
{
protected override Accounts InnerGet()
{
throw new NotImplementedException();//Get the data from BL
}
protected override void InnerDelete()
{
throw new NotImplementedException();
}
}
To do this in the New API we've introduced the concept of a IServiceRunner that decouples the execution of your service from the implementation of it.
To add your own Service Hooks you just need to override the default Service Runner in your AppHost from its default implementation:
public virtual IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
With your own:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
Where MyServiceRunner is just a custom class implementing the custom hooks you're interested in, e.g:
public class MyServiceRunner<T> : ServiceRunner<T> {
public override void OnBeforeExecute(IRequestContext requestContext, TRequest request) {
// Called just before any Action is executed
}
public override object OnAfterExecute(IRequestContext requestContext, object response) {
// Called just after any Action is executed, you can modify the response returned here as well
}
public override object HandleException(IRequestContext requestContext, TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}
Also for more fine-grained Error Handling options check out the Error Handling wiki page.
My solution was to add an additional layer where I can handle Logic per entity:
Base Logic Sample:
public interface IEntity
{
long Id { get; set; }
}
public interface IReadOnlyLogic<Entity> where Entity : class, IEntity
{
List<Entity> GetAll();
Entity GetById(long Id);
}
public abstract class ReadOnlyLogic<Entity> : IReadOnlyLogic<Entity> where Entity : class, IEntity, new()
{
public IDbConnection Db { get; set; }
#region HOOKS
protected SqlExpression<Entity> OnGetList(SqlExpression<Entity> query) { return query; }
protected SqlExpression<Entity> OnGetSingle(SqlExpression<Entity> query) { return OnGetList(query); }
#endregion
public List<Entity> GetAll()
{
var query = OnGetList(Db.From<Entity>());
return Db.Select(query);
}
public Entity GetById(long id)
{
var query = OnGetSingle(Db.From<Entity>())
.Where(e => e.Id == id);
var entity = Db.Single(query);
return entity;
}
}
Then we can use hooks like:
public interface IHello : IReadOnlyLogic<Hello> { }
public class HelloLogic : ReadOnlyLogic<Hello>, IHello
{
protected override SqlExpression<Hello> OnGetList(SqlExpression<Hello> query)
{
return query.Where(h => h.Name == "Something");
}
}
Finally our service only calls our logic:
public class MyServices : Service
{
IHello helloLogic;
public object Get()
{
return helloLogic.GetAll();
}
}

How can I inject multiple repositories in a NServicebus message handler?

I use the following:
public interface IRepository<T>
{
void Add(T entity);
}
public class Repository<T>
{
private readonly ISession session;
public Repository(ISession session)
{
this.session = session;
}
public void Add(T entity)
{
session.Save(entity);
}
}
public class SomeHandler : IHandleMessages<SomeMessage>
{
private readonly IRepository<EntityA> aRepository;
private readonly IRepository<EntityB> bRepository;
public SomeHandler(IRepository<EntityA> aRepository, IRepository<EntityB> bRepository)
{
this.aRepository = aRepository;
this.bRepository = bRepository;
}
public void Handle(SomeMessage message)
{
aRepository.Add(new A(message.Property);
bRepository.Add(new B(message.Property);
}
}
public class MessageEndPoint : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
public void Init()
{
ObjectFactory.Configure(config =>
{
config.For<ISession>()
.CacheBy(InstanceScope.ThreadLocal)
.TheDefault.Is.ConstructedBy(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());
config.ForRequestedType(typeof(IRepository<>))
.TheDefaultIsConcreteType(typeof(Repository<>));
}
}
My problem with the threadlocal storage is, is that the same session is used during the whole application thread. I discovered this when I saw the first level cache wasn't cleared. What I want is using a new session instance, before each call to IHandleMessages<>.Handle.
How can I do this with structuremap? Do I have to create a message module?
You're right in that the same session is used for all requests to the same thread. This is because NSB doesn't create new threads for each request. The workaround is to add a custom cache mode and have it cleared when message handling is complete.
1.Extend the thread storage lifecycle and hook it up a a message module
public class NServiceBusThreadLocalStorageLifestyle : ThreadLocalStorageLifecycle, IMessageModule
{
public void HandleBeginMessage(){}
public void HandleEndMessage()
{
EjectAll();
}
public void HandleError(){}
}
2.Configure your structuremap as follows:
For<<ISession>>
.LifecycleIs(new NServiceBusThreadLocalStorageLifestyle())
...
Hope this helps!