I am doing a Spring project for the first time and am stuck with a problem.
I have a java class:
#Component
#Conditional(AppA.class)
public class AppDeploy {...}
Now I need to modify this like:
#Component
#Conditional(AppA.class or AppB.class)
public class AppDeploy {...}
Can someone help me with how to do this?
Thanks in anticipation.
You can create your own conditional annotation which enables you to provide parameters and then you can apply the tests conditions depending on the provided parameter value:
see this post for more details: http://www.javacodegeeks.com/2013/10/spring-4-conditional.html
It was very simple, Should have taken a little time before posting the question.
Here is how I did it.
Created a new Class:
public class AppAOrB implements Condition {
public AppAOrB() {
super();
}
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = conditionContext.getEnvironment();
return env.containsProperty("APP_A")||env.containsProperty("APP_B");
}
}
Then used it like:
#Component
#Conditional(AppAOrB.class)
public class AppDeploy {...}
I have a slightly different approach.
From your code, I can conclude(Maybe I am wrong) that You have already implemented conditions AppA.class and AppB.class and You wonder how to implement the AppAOrB.class condition in an elegant way. When You take into account that AppA.class and AppB.class are just regular java classes, then implementation is obvious:
public class AppAOrB implements Condition {
#Override
public boolean matches(#NonNull ConditionContext context, #NonNull AnnotatedTypeMetadata metadata) {
return new AppA().matches(context, metadata) || new AppB().matches(context, metadata);
}
}
The pros of this approach is that it follows the DRY rule.
Related
I would like to intercept calls to methods conversation.begin() and conversation.end().
To do this, I have developed an interceptor binding that I aim to dynamically assign to the Conversation class through a CDI portable extension.
However, I can not find how to access to the Conversation class since it is not observed in the ProcessAnnotatedType event where usually i do this process to my defined beans.
See the code as an example:
public class MethodCallsInterceptorExt implements Extension {
void processAnnotatedType(#Observes ProcessAnnotatedType<?> event) {
if (isConvesationBean(event)) { // This condition is never true
event.configureAnnotatedType().add(new MyInterceptorBinding());
}
}
}
Is this solution at least partially correct?
Is there any viable way to do this?
You could do something like this:
public class ConversationObserver {
public void onStart(#Observes #Initialized(ConversationScoped.class) ServletRequest request) {}
public void onEnd(#Observes #Destroyed(ConversationScoped.class) ServletRequest request) {}
}
See https://docs.jboss.org/cdi/api/2.0/javax/enterprise/context/ConversationScoped.html
I have this old code implemented in hateoas:1.0
public class StaticPathLinkBuilder extends LinkBuilderSupport<StaticPathLinkBuilder> {
#Override
protected StaticPathLinkBuilder createNewInstance(UriComponentsBuilder builder) {
return new StaticPathLinkBuilder(builder);
}
I updated my code to hateoas 2.6.7 but the code is changed this way:
public class StaticPathLinkBuilder extends LinkBuilderSupport<StaticPathLinkBuilder> {
#Override
protected StaticPathLinkBuilder createNewInstance(UriComponents components, List<Affordance> affordances) {
return null;
}
What is the proper way to implement this change? I tried this:
#Override
protected StaticPathLinkBuilder createNewInstance(UriComponents components, List<Affordance> affordances) {
return new StaticPathLinkBuilder(UriComponentsBuilder.newInstance().uriComponents(components));
}
But it's not clear how I have to implement the code that I can send affordances.
Can you advice what is the proper way to implement this?
As you can see in its source code LinkBuilderSupport already provides a constructor with the two required arguments, UriComponents and List<Affordance>.
In the own library codebase, different LinkBuilders implementations as BasicLinkBuilder or TemplateVariableAwareLinkBuilderSupport already takes advantage of this fact in their implementations.
In your use case, you could try something similar to this:
public class StaticPathLinkBuilder extends LinkBuilderSupport<StaticPathLinkBuilder> {
private StaticPathLinkBuilder(UriComponents components, List<Affordance> affordances) {
super(components, affordances);
}
#Override
protected StaticPathLinkBuilder createNewInstance(UriComponents components, List<Affordance> affordances) {
return new StaticPathLinkBuilder(components, affordances);
}
}
I have multiple classes which implement an interface and return an Object.
public interface DataFetcher {
Data getData(Info info);
}
public class Data {
private String name;
private String value;
}
#Component
public class DataPointA implements DataFetcher {
#Override
public Data getData(Info info) {
//..Do some processing
return new Data("SomeName", valueComputed);
}
}
Now I have about 20 data points which implement the DataFetcher class and returns the Data Object.
I autowire all the data points to a class and based on certain conditions I use certain data points.
#Component
public class DataComputer {
#Autowired
private DataPointA dataPointA;
#Autowired
private DataPointB dataPointB;
.
.
.
public void computeData(String inputType, Info info) {
List<DataFetcher> dataFecthers;
switch(inputType) {
case "typeA" : dataFecthers = ImmutableList.of(dataPointA, dataPointB);
break;
.
.
.
case "typeD" : dataFecthers = ImmutableList.of(dataPointE, dataPointF, dataPointG);
break;
}
dataFetcher.forEach(dataPoint -> {
//Do some processing with dataPoint.getData(info)
})
}
}
As can be seen DataComputer class will have a whole list of dependencies which can become unmanageable. Also the data point to be used based on the inputType is known before hand so this can be extracted out. This was my attempt at doing it:
#Component
public class DataComputationPointDecider {
#Autowired
private DataPointA dataPointA;
#Autowired
private DataPointB dataPointB;
.
.
.
#Bean
public Map<String, List<DataFetcher>> getDataComputationPoints() {
return new ImmutableMap.Builder<String, List<DataFetcher>>()
.put("typeA", ImmutableList.of(dataPointA, dataPointB))
.put("typeD", ImmutableList.of(dataPointE, dataPointF, dataPointG))
.build();
}
}
And then my DataComputer dependencies reduces:
#Component
public class DataComputer {
#Autowired
private Map<String, List<DataFetcher>> dataComputationPoints;
public void computeData(String inputType, Info info) {
List<DataFetcher> dataFecthers = dataComputationPoints.get(inputType);
dataFetcher.forEach(dataPoint -> {
//Do some processing with dataPoint.getData(info)
})
}
}
Is there a better way to design this?
I don't see anything majorly wrong in your approach. But I'm suggesting one more option.
Instead of maintaining a map that maps an inputType with a list of DataFetcher, you can make a DataFetcher decide or say what input type(s) it can handle.
But this needs changing the interface of DataFetcher as
public interface DataFetcher {
boolean canHandle(String inputType);
Data getData(Info info);
}
The implementations would look like
#Component
public class DataPointA implements DataFetcher {
#Override
boolean canHandle(String inputType) {
return "typeA".equals(inputType);
}
#Override
public Data getData(Info info) {
//..Do some processing
return new Data("SomeName", valueComputed);
}
}
Then you can just inject all DataFetcher as one single list (and need not add one #Autowired field for each one) and process it as
#Autowired
List<DataFetcher> dataFetchers;
...
dataFetchers.stream()
.filter(dataFetcher -> dataFetcher.canHandle(inputType))
.forEach(dataFetcher.getData(info));
Advantages:
In your current approach, if you add a new DataFetcher implementation, you need to add a #AutoWired field/member and modify the (getDataComputationPoints)map. But, with this, the inputTypes a DataFetcher can handle is specified with that itself and hence you just need to add new classes for new input types.
Reference
Autowire reference beans into list by type
UPDATE:
Disadvantages
The input types are specified inside the class means that you cannot easily find the list of DataFetchers (data points) for a given input type.
If you need to remove support for an inputType, then again you need to visit each implementation (to remove that inputType from canHandle). In your approach, it is about simply remove one map entry.
Have you considered using the Factory pattern? This allows you to submit a request for an object instance based on certain criteria.
The following is an approximation of the problem I'm facing.
Think we have a password validator with some rules.
public interface RuleChecker{
//Checks for a password strenght, returns 10
//for strong or 0 for soft password.
int check(String pass);
}
And then we have several implementations, our service will only accept the password if it is over 8 score.
public class NoCheck implements RuleChecker {
public int check(String pass){return 10;}
}
public class LengthCheck implements RuleChecker{
...
}
public class AlphanumericCheck implements RuleChecker{
...
}
public class AlphaAndLenghtCheckAdapter implements RuleChecker{
...
}
But for testing purposes, we want to implement a webservice within the application where we can "admin" those rules, and select which ones to have.
public class PasswordCheckService{
private RuleChecker checker;
#Inject
public PasswordCheckService(final RuleChecker checker){
this.checker = checker;
}
public boolean checkPassword(String password){
return checker.check(password) > 8;
}
}
So, is there any way in Guice, to change at runtime, the injection a service has?
Example:
We started the application and by default LengthCheck is selected and injected on the application, at the website we select the NoCheck checkbox and save options, which is stored into the database, can I configure Guice to automatically change the bean the service had injected before? so from now and on there will be no checks on new passwords?
--
As for now, I have found those topics
Google Guice and varying injections at runtime
But i dont know if that kind of providers fits my problem.
Guice runtime dependency parameters reinjection
That nice question is talking something similar, but not what I'm looking form.
guice: runtime injection/binding at command line
This is the closest to my problem but he only does on starting "runtime" and does not change it over the time.
Any helps?
Thank you!
Using the tip of the first comment I implemented this POC but still does not works, if you change select another button the service bean is not updated.
https://bitbucket.org/ramonboza/guicedynamicconfig
Create a provider for each field type (login, password, birth date...), with a parameter to change the implementation to return.
public class MyModule extends AbstractModule {
public void configure() {
bind(RuleChecker.class).annotatedWith(named("password")).toProvider(PasswordRuleCheckerProvider.class);
bind(RuleChecker.class).annotatedWith(named("login")).toProvider(LoginRuleCheckerProvider.class);
}
}
public static class PasswordRuleCheckerProvider implements Provider<RuleChecker> {
private static CheckType type = CheckType.ALPHANUMERIC;
// static type setter.
public RuleChecker get() {
// it would even be better if you could use singletons here.
switch(type) {
case LENGTH:
return new LengthCheck();
case ALPHANUMERIC:
return new AlphanumericCheck();
case ALPHALENGTH:
return new AlphaAndLenghtCheckAdapter();
case NONE:
default:
return NoCheck();
}
}
}
// Almost same provider for your LoginRuleCheckerProvider. You could do something generic.
In your admin section you change "type" value, so your rules will change. It can affect a limited set of fields, thanks to the annotations. For instance : PasswordRuleCheckerProvider.setType(CheckType.LENGTH);. Will only affect fields with #Named('password').
You have to declare your fields and services like this :
public abstract class DynamicService {
protected void updateService() {
// Reinject with the new implementations the members.
App.getInjector().injectMembers(this);
}
}
public class PasswordCheckService extends DynamicService {
#Inject
#Named("password")
private RuleChecker passwordChecker;
public void changePasswordCheckType(CheckType type) {
PasswordRuleCheckerProvider.setType(type);
// Reinject, so you have your new implementation.
updateService();
}
// [...]
}
Suppose I have a validation annotation on my Interface method to validate input arguments and return value.
Is it possible at the moment (V 1.9.5) to tell Mockito to invoke this validator during the invocation process?
The background would be to prevent developers from writing unrealistic tests by mocking the given interface in a way that violates the specified validator.
So what I would want is to register something like
class MyAnswerInterceptor<T> implements AnswerInterceptor<T> {
#Override
public Answer<T> intercept(final Answer<T> answer) {
return new Answer<T>() {
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
validateArguments(invocation);
T result = answer.answer(invocation);
validateReturnValue(result);
return result;
}
}
}
}
to be called on every answer of a given mock.
Is this possible at all? I've looked into the code, also to check if I could hack in at some point (even using reflection or the like), but it seems due to entanglement of instance creation and logic, it's hardly possible to achieve what I want (i.e. stuff like MockHandler mockHandler = new MockHandlerFactory().create(settings); makes it impossible to hook in and put custom stuff on top without patching and deploying the whole thing...)
Any insight would be highly appreciated :-)
You could achieve that by creating a custom MockMaker.
MockMaker is an extension point that makes it possible to use custom dynamic proxies and avoid using the default cglib/asm/objenesis implementation
Our custom implementation delegates all the complex stuff to the default MockMaker: CglibMockMaker. It "decorates" only the createMock method by registering on the settings parameter an InvocationListener. This listener will be notified when an invocation have been done allowing use to call validateArguments and validateReturnValue.
import org.mockito.internal.creation.CglibMockMaker;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.MockHandler;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockMaker;
public class ValidationMockMaker implements MockMaker {
private final MockMaker delegate = new CglibMockMaker();
public ValidationMockMaker() {
}
#Override
public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
settings.getInvocationListeners().add(new InvocationListener() {
#Override
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
Invocation invocation = (Invocation) methodInvocationReport.getInvocation();
validateArguments(invocation.getArguments());
validateReturnValue(methodInvocationReport.getReturnedValue());
}
});
return delegate.createMock(settings, handler);
}
#Override
public MockHandler getHandler(Object mock) {
return delegate.getHandler(mock);
}
#Override
public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) {
delegate.resetMock(mock, newHandler, settings);
}
protected void validateArguments(Object... arguments) {
// Arrays.stream(arguments).forEach(Objects::requireNonNull);
}
private void validateReturnValue(Object result) {
// Objects.requireNonNull(result);
}
}
Last but not least, we need to tell to Mockito to use our implementation. This is possible by adding a file
mockito-extensions/org.mockito.plugins.MockMaker
containing our MockMaker class name:
ValidationMockMaker
See Using the extension point section in the javadoc.