I'm playing with the new Hibernate 5 Bootstrap API and was excited to see how easily (compared to previous/legacy API) can assemble SessionFactory and family.
Now, I would like to provide my own ListenerFactory which basically delegates creation and dependency injection of entity listeners to Guice.
I couldn't find how to do it except for applyBeanManager from SessionFactoryBuilder:
sessionFactoryBuilder.applyBeanManager(new ListenerFactory() {
#Override
public void release() {
}
#Override
public <T> Listener<T> buildListener(final Class<T> listenerClass) {
return () -> injector.getInstance(listenerClass);
}
});
Unfortunately, this didn't work bc Hibernate expect ListenerFactory to be null (and uses a default ListenerFactory) or be an instance of BeanManager.
Wonder if there is another way of provide my own ListenerFactory?
Thanks.
That's because the BeanManager is designed for CDI. If you want to customize it beyond CDI, you need to open JIRA issue describing your use case and what you want to do.
Alternatively, if you want to inject dependencies into your entities (which I find really odd since it breaks layer encapsulation), you could just use the LoadEventListener to customize the way an entity is created:
sessionFactory
.getServiceRegistry()
.getService( EventListenerRegistry.class )
.prependListeners( EventType.LOAD, new MyGuiceEntityListener() );
Related
I want to use Guice Multibinding injection in javax.validation.ConstraintValidator.
Not getting any clue to inject map binder in my ConstraintValidator class.
I use the MapBinder in the following way, it does it's job, but I need to refactor to make it better. To give you some background, I had to match a legacy program for copying data from a primary database to any number of subsequent databases using a combination of files (don't ask, but it works). Anyhow, I use a super simple mapping scheme of TableName -> TableTransferHandler, here is how I define the bindings:
MapBinder<String, TableTransferHandler<?>> binder
= MapBinder.newMapBinder(
binder(),
new TypeLiteral<String>() {},
new TypeLiteral<TableTransferHandler<?>>(){});
// Add my Table handlers based on table name.
binder.addBinding("table_one").to(TableOneTransferHandlerImpl.class);
binder.addBinding("table_two").to(TableTwoTransferHandlerImpl.class);
which gets used as such:
#Inject
Map<String,TableTransferHandler<?>> handlers;
TableTransferHandler<?> handler = handlers.get(tableName);
handler.process();
It's very trivial, and needs to be rewritten, but for the most part it gets the job done. From what you've explained though, I'm not sure if you want MapBinder, you probably want to return the regular binding for a ConstraintValidator. If I had chosen to implement a TableTransferHandler by remote system, instead of by name, I would have done this:
Multibinder<TableTransferHandler<UserAccess>> binder
= Multibinder.newSetBinder(
binder(),
new TypeLiteral<TableTransferHandler<UserAccess>>() {});
// Add all my remote handlers relating to UserAccess
binder.addBinding().to(RemoteOneUserAccessTableHandler.class);
binder.addBinding().to(RemoteTwoUserAccessTableHandler.class);
Which would then be used:
#Inject
Set<TableTransferHandler<UserAccess>> handlers;
for (TableTransferHandler<UserAccess> handler : handlers) {
handler.process();
}
We are using Spring Cloud Stream as the underlying implementation for event messaging in our microservice-based architecture. We wanted to go a step further and provide an abstraction layer between our services and the Spring Cloud Stream library to allow for dynamic channel subscriptions without too much boilerplate configuration code in the services themselves.
The original idea was as follows:
The messaging-library provides a BaseHandler abstract class which all individual services must implement. All handlers of a specific service would like to the same input channel, though only the one corresponding to the type of the event to handle would be called. This looks as follows:
public abstract class BaseEventHandler<T extends Event> {
#StreamListener
public abstract void handle(T event);
}
Each service offers its own events package, which contains N EventHandlers. There are plain POJOs which must be instantiated programmatically. This would look as follows:
public class ServiceEventHandler extends BaseEventHandler<ImportantServiceEvent> {
#Override
public void handle(ImportantServiceEvent event) {
// todo stuff
}
}
Note that these are simple classes and not Spring beans at this point, with ImportantServiceEvent implementing Event.
Our messaging-library is scanned on start-up as early as possible, and performs handler initialization. To do this, the following steps are done:
We scan all available packages in the classpath which provide some sort of event handling and retrieve all subclasses of BaseEventHandler.
We retrieve the #StreamListener annotation in the hierarchy of the subclass, and change its value to the corresponding input channel for this service.
Since our handlers might need to speak to some other application components (repositories etc.), we use DefaultListableBeanFactory to instantiate our handlers as singleton, as follows:
val bean = beanFactory.createBean(eventHandlerClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
beanFactory.registerSingleton(eventHandlerClass.getSimpleName(), bean);
After this, we ran into several issues.
The Spring Cloud Stream #StreamListener annotation cannot be inherited as it is a method annotation. Despite this, some mechanism seems to be able to find it on the parent (as the StreamListenerAnnotationBeanPostProcessor is registered) and attempts to perform post-processing upon the ServiceEventHandler being initialized. Our assumption is that the Spring Cloud Stream uses something like AnnotationElementUtils.findAllMergedAnnotations().
As a result of this, we thought that we might be able to alter the annotation value of the base class prior to each instantiation of a child class. Due to this, we thought that although our BaseEventHandler would simply get a new value which would then stay constant at the end of this initialization phase, the child classes would be instantiated with the correct channel name at the time of instantiation, since we do not expect to rebind. However, this is not the case and the value of the #StreamListener annotation that is used is always the one on the base.
The question is then: is what we want possible with Spring Cloud Stream? Or is it rather a plain Java problem that we have here (does not seem to be the case)? Did the Spring Cloud Stream team foresee a use case like this, and are we simply doing it completely wrong?
This question was also posted on on the Spring Cloud Stream tracker in case it might help garner a bit more attention.
Since the same people monitor SO and GitHub issues, it's rather pointless to post in both places. Stack Overflow is preferred for questions.
You should be able to subclass the BPP; it specifically has this extension point:
/**
* Extension point, allowing subclasses to customize the {#link StreamListener}
* annotation detected by the postprocessor.
*
* #param originalAnnotation the original annotation
* #param annotatedMethod the method on which the annotation has been found
* #return the postprocessed {#link StreamListener} annotation
*/
protected StreamListener postProcessAnnotation(StreamListener originalAnnotation, Method annotatedMethod) {
return originalAnnotation;
}
Then override the bean definition with yours
#Bean(name = STREAM_LISTENER_ANNOTATION_BEAN_POST_PROCESSOR_NAME)
public static StreamListenerAnnotationBeanPostProcessor streamListenerAnnotationBeanPostProcessor() {
return new StreamListenerAnnotationBeanPostProcessor();
}
It's the first time I have to use Dependency Injection and I'm a little confused.
I don't really understand how it works.
I have tried on a simple example :
public class StockResponse extends Response
{
#Inject BrandService $brand;
public List<StockResponseItem> stock;
public StockThresholdResponse()
{
stock = new ArrayList<>();
}
public static StockThresholdResponse create(List<DataItem> data)
{
StockResponse stock= new StockResponse();
for (ThresholdCheckAggregate data: d)
{
StockResponseItem item = new StockResponseItem();
item.id = d.thresholdId;
item.brand = str.$brand.byId(d.brand);
str.stockThresholds.add(item);
}
return str;
}
}
But when I use my create() method, I get a null pointer exception for $brand.
I think I have misunderstood how DI works but I can't find my error.
I had similar difficulties to understand how DI (Guice out of Java EE) works. In simple words Guice must have chance to modify You object, for example:
assist by construction usually.
You ask Guice "can You create my object" injector.getInstance(cls), then Guice is creating object for You, solving field or constructor annotation
In normal (non Java EE) environment Yoy never call classic constructor, You ask by second hand.
other method.
Few library / frameworks have integration with Guice (Apache Wicket I personally like) with "creation listeners" on some types of objects. Hard work of DI is hidden for Your eyes, but is executed.
Java EE lets say better EE programmers than me :(
In consequence Yoy don't give chance to inject anything, is null
Professionals sorry that I say at blondie level. That is way like I discovered DI few years ago
Correction to code. Not
StockResponse stock= new StockResponse();
but
mod = .... // Module
injector = Guice.createInjector(mod); // global or almost global
...
injector.getInstance(StockResponse.class);
EDIT: intentionally I don't answer "how to write Guice module", assume this is other, long story
This could work, assuming BrandService is either a concrete class or if it's an interface, you have provided a binding for it to a concrete class elsewhere in your DI configuration (say a module in Guice or Spring #Configuration). I do see one obvious NullPointerException with str variable. Did you mean to do this?
item.brand = stock.$brand.byId(d.brand);
I have written some code which I thought was quite well-designed, but then I started writing unit tests for it and stopped being so sure.
It turned out that in order to write some reasonable unit tests, I need to change some of my variables access modifiers from private to default, i.e. expose them (only within a package, but still...).
Here is some rough overview of my code in question. There is supposed to be some sort of address validation framework, that enables address validation by different means, e.g. validate them by some external webservice or by data in DB, or by any other source. So I have a notion of Module, which is just this: a separate way to validate addresses. I have an interface:
interface Module {
public void init(InitParams params);
public ValidationResponse validate(Address address);
}
There is some sort of factory, that based on a request or session state chooses a proper module:
class ModuleFactory {
Module selectModule(HttpRequest request) {
Module module = chooseModule(request);// analyze request and choose a module
module.init(createInitParams(request)); // init module
return module;
}
}
And then, I have written a Module that uses some external webservice for validation, and implemented it like that:
WebServiceModule {
private WebServiceFacade webservice;
public void init(InitParams params) {
webservice = new WebServiceFacade(createParamsForFacade(params));
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
So basically I have this WebServiceFacade which is a wrapper over external web service, and my module calls this facade, processes its response and returns some framework-standard response.
I want to test if WebServiceModule processes reponses from external web service correctly. Obviously, I can't call real web service in unit tests, so I'm mocking it. But then again, in order for the module to use my mocked web service, the field webservice must be accessible from the outside. It breaks my design and I wonder if there is anything I could do about it. Obviously, the facade cannot be passed in init parameters, because ModuleFactory does not and should not know that it is needed.
I have read that dependency injection might be the answer to such problems, but I can't see how? I have not used any DI frameworks before, like Guice, so I don't know if it could be easily used in this situation. But maybe it could?
Or maybe I should just change my design?
Or screw it and make this unfortunate field package private (but leaving a sad comment like // default visibility to allow testing (oh well...) doesn't feel right)?
Bah! While I was writing this, it occurred to me, that I could create a WebServiceProcessor which takes a WebServiceFacade as a constructor argument and then test just the WebServiceProcessor. This would be one of the solutions to my problem. What do you think about it? I have one problem with that, because then my WebServiceModule would be sort of useless, just delegating all its work to another components, I would say: one layer of abstraction too far.
Yes, your design is wrong. You should do dependency injection instead of new ... inside your class (which is also called "hardcoded dependency"). Inability to easily write a test is a perfect indicator of a wrong design (read about "Listen to your tests" paradigm in Growing Object-Oriented Software Guided by Tests).
BTW, using reflection or dependency breaking framework like PowerMock is a very bad practice in this case and should be your last resort.
I agree with what yegor256 said and would like to suggest that the reason why you ended up in this situation is that you have assigned multiple responsibilities to your modules: creation and validation. This goes against the Single responsibility principle and effectively limits your ability to test creation separately from validation.
Consider constraining the responsibility of your "modules" to creation alone. When they only have this responsibility, the naming can be improved as well:
interface ValidatorFactory {
public Validator createValidator(InitParams params);
}
The validation interface becomes separate:
interface Validator {
public ValidationResponse validate(Address address);
}
You can then start by implementing the factory:
class WebServiceValidatorFactory implements ValidatorFactory {
public Validator createValidator(InitParams params) {
return new WebServiceValidator(new ProdWebServiceFacade(createParamsForFacade(params)));
}
}
This factory code becomes hard to unit-test, since it is explicitly referencing prod code, so keep this impl very concise. Put any logic (like createParamsForFacade) on the side, so that you can test it separately.
The web service validator itself only gets the responsibility of validation, and takes in the façade as a dependency, following the Inversion of Control (IoC) principle:
class WebServiceValidator implements Validator {
private final WebServiceFacade facade;
public WebServiceValidator(WebServiceFacade facade) {
this.facade = facade;
}
public ValidationResponse validate(Address address) {
WebService wsResponse = webservice.validate(address);
ValidationResponse reponse = proccessWsResponse(wsResponse);
return response;
}
}
Since WebServiceValidator is not controlling the creation of its dependencies anymore, testing becomes a breeze:
#Test
public void aTest() {
WebServiceValidator validator = new WebServiceValidator(new MockWebServiceFacade());
...
}
This way you have effectively inverted the control of the creation of the dependencies: Inversion of Control (IoC)!
Oh, and by the way, write your tests first. This way you will naturally gravitate towards a testable solution, which is usually also the best design. I think that this is due to the fact that testing requires modularity, and modularity is coincidentally the hallmark of good design.
My application loads entities from a Hibernate DAO, with OpenSessionInViewFilter to allow rendering.
In some cases I want to make a minor change to a field -
Long orderId ...
link = new Link("cancel") {
#Override public void onClick() {
Order order = orderDAO.load(orderId);
order.setCancelledTime(timeSource.getCurrentTime());
};
but such a change is not persisted, as the OSIV doesn't flush.
It seems a real shame to have to call orderDOA.save(order) in these cases, but I don't want to go as far as changing the FlushMode on the OSIV.
Has anyone found any way of declaring a 'request handling' (such as onClick) as requiring a transaction?
Ideally I suppose the transaction would be started early in the request cycle, and committed by the OSIV, so that all logic and rendering would take place in same transaction.
I generally prefer to use additional 'service' layer of code that wraps basic DAO
logic and provides transactions via #Transactional. That gives me better separation of presentation vs business logic and is
easier to test.
But since you already use OSIV may be you can just put some AOP interceptor around your code
and have it do flush()?
Disclaimer : I've never actually tried this, but I think it would work. This also may be a little bit more code than you want to write. Finally, I'm assuming that your WebApplication subclasses SpringWebApplication. Are you with me so far?
The plan is to tell Spring that we want to run the statements of you onClick method in a transaction. In order to do that, we have to do three things.
Step 1 : inject the PlatformTransactionManager into your WebPage:
#SpringBean
private PlatformTransactionManager platformTransactionManager;
Step 2 : create a static TransactionDefinition in your WebPage that we will later reference:
protected static final TransactionDefinition TRANSACTION_DEFINITION;
static {
TRANSACTION_DEFINITION = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
((DefaultTransactionDefinition) TRANSACTION_DEFINITION).setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
}
Feel free to change the TransactionDefinition settings and/or move the definition to a shared location as appropriate. This particular definition instructs Spring to start a new transaction even if there's already one started and to use the maximum transaction isolation level.
Step 3 : add transaction management to the onClick method:
link = new Link("cancel") {
#Override
public void onClick() {
new TransactionTemplate(platformTransactionManager, TRANSACTION_DEFINITION).execute(new TransactionCallback() {
#Override
public Object doInTransaction(TransactionStatus status) {
Order order = orderDAO.load(orderId);
order.setCancelledTime(timeSource.getCurrentTime());
}
}
}
};
And that should do the trick!