I want to use CassandraBatchTemplate's withTimestamp to insert client side timestamp like USING TIMESTAMP clause in the CQL. here is my code:
#Bean
public DseSession dseSession(DseCluster dseCluster) {
return dseCluster.connect(keyspace);
}
#Bean
public CassandraOperations cassandraTemplate(DseSession session) {
return new CassandraTemplate(session);
}
#Bean
public CassandraBatchOperations cassdraBatchTemplate(CassandraOperations cassandraTemplate) {
return new CassandraBatchTemplate(cassandraTemplate);
}
when compiled it complained cannot find CassandraBatchTemplate even though i can see it in spring-data-cassandra source code. one thing i noticed is that CassandraBatchTemplate is default implementation of interface CassandraBatchOperations, thus no 'public' is applied to CassandraBatchTemplate class:
class CassandraBatchTemplate implements CassandraBatchOperations {...}
if the class is not public then I cannot create an instance of it by 'new'. how to work around? I'm using spring-data-cassandra 2.1.10.RELEASE and dse-java-driver-core 1.8.2
CassandraBatchTemplate isn't public because it has a very limited lifecycle. It isn't intended to be used as #Bean because it is only valid for a single execution.
Instead, obtain CassandraBatchOperations through CassandraOperations.batchOps().
Related
I want to return multiple spring beans based on the condition in the factory class.
Is this a good practice?
Any better ways to write the following piece of code?.
Any other design patterns suitable here?
Below is the code snippet:
package com.test;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
#Component
public class InstanceFactory {
#Resource(name = "instance1")
private Instance instance1;
#Resource(name = "instance2")
private Instance instance2;
public Instance getService(Condition condition) {
if (condition.one() && condition.two()) {
return instance2;
} else {
return instance1;
}
}
}
It depends on what you want to achieve. Factory Pattern is meant to create objects but what you are returning are objects already create somewhere else (Spring in this case). If you want to create beans that will be managed by Spring there are several ways:
#Conditional(YourConditionImplementation.class): This annotation added on a method of a #Configuration annotated class will allow you to create a bean when the given condition is fullfilled. Example here: https://javapapers.com/spring/spring-conditional-annotation/
You can uses as well BeanFactory to inject the definition of your bean (DefinitionBean) into the container. Example here: https://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition.html
Now, if you want an object that determine what object of type Instance fits better for some need then your approach is ok, but it is not technically a factory :)
When designing something like that I would face that solution considering two design patterns:
Strategy pattern: In order to replace repetitive if else every time you need to evaluate more instances.
Decorator pattern: Trying to make every condition as configurable as possible. They can be composed (decorated) for one or more predicates.
Considering these two pattens you might achieve something like this:
First, define which conditions will identify a given instance:
public enum InstanceType {
INSTANCE_TYPE_1(Condition::isOne, Condition::isTwo),
INSTANCE_TYPE_2(Condition::isOne, Condition::isThree),
...;
private List<Predicate<Condition>> evaluators;
#SafeVarargs
InstanceType(final Predicate<Condition>... evaluators) {
this.evaluators = Arrays.asList(evaluators);
}
public boolean evaluate(final Condition condition) {
return evaluators.stream().allMatch(it -> it.test(condition));
}
}
Then, you should link every instance implementation to an specific instance type:
#Component
public class InstanceOne implements Instance {
#Override
public InstanceType getType() {
return InstanceType.INSTANCE_TYPE_1;
}
}
Finally, a class to config where defining the relation between types and instances as EnumMap
#Configuration
public class InstanceFactoryConfig {
#Autowired
private List<Instance> instances;
#Bean
public EnumMap<InstanceType, Instance> instancesMap() {
EnumMap<InstanceType, Instance> instanceEnumMap = new EnumMap<>(InstanceType.class);
instances.forEach(i -> instanceEnumMap.put(i.getType(), i));
return instanceEnumMap;
}
}
Thus, you InstanceFactory can be replaced to something like this:
public class InstanceFactory {
#Autowire
private final EnumMap<InstanceType, Instance> instancesMap;
public void getInstance(Condition condition) {
instancesMap.get(getInstanceType(condition)).doSomething();
}
private InstanceType getInstanceType(Condition condition) {
return Arrays.stream(InstancesType.values())
.filter(evaluator -> evaluator.evaluate(condition))
.findFirst().orElseThrow(() -> new RuntimeException("Instance type not found"));
}
}
As you can see, you InstanceFactory is less prone to be modified. This means, every time you need you add a new instance implementation you only need to modify the InstanceType enum. Hope this is helps.
You can use spring existing FactoryBean interface and implement your own logic
It’s one of the best approaches to create beans in spring framework
Here is the link with example :
https://www.baeldung.com/spring-factorybean
See:
Spring Profile
The active profile is set by properties and based on the value you assign to the profile, Spring will load different beans for the same interface.
So it might be exactly what you need.
I want to implement a conditional Bean depending on a flag in my application.properties. Example:
// application.properties
service=foobar
The idea is to make different service implementations configurable, let assume I got a central configuration class for this service in Spring:
#Configuration
#Import({ServiceA.class, ServiceB.class, ...})
public class ServiceConfiguration {
...
}
And possible service implementations would look like
#Configuration
public class ServiceA implements Condition {
#Bean
#Conditional(ServiceA.class)
public Service service() {
Service a = ...
return a;
}
#Override
public boolean matches(
ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata) {
// getProperty will alsways return null for some reason
return conditionContext
.getEnvironment()
.getProperty("service")
.equals("ServiceA");
}
// This will be null anyways
#Value("${service}")
private String confService;
}
Since the class implementing Condition (here just the same class ServiceA) will be initialized via default constructor #Value-injections won't work. How ever, by what I understand getProperty()should return the correct value. What am I doing wrong? How can I access application properties at this point?
I found at "dirty workarround", I really don't like that solution, how ever, it solves the problem. As mentioned here a #PropertySource fixes the problem (I haven't tried this before posting here since it wasn't an accpeted answer).
#Configuration
#PropertySource(value="file:config/application.properties")
public class ServiceA implements Condition {
#Bean
#Conditional(ServiceA.class)
public Service service() {
Service a = ...
return a;
}
#Override
public boolean matches(
ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata) {
// Will work now
return conditionContext
.getEnvironment()
.getProperty("service")
.equals("ServiceA");
}
}
Although this works I don't like it for several reason:
With every implementation I have code redundancy (giving a path to a config file)
It's highly unmaintainable when having multiple configuration files
Example: Behavior like load default.properties <-then load and overwrite with -> customer.properties won't work anymore (altough this should be solvable using #PropertySources which would, on the other hand, increase code redundancy)
In the following Spring Java Config:
#Configuration
#EnableAutoConfiguration
#ComponentScan("my.package")
public class Config {
#Bean
public BasicBean basicBean1() {
return new BasicBean("1");
}
#Bean
public BasicBean basicBean2() {
return new BasicBean("2");
}
#Bean
public ComplexBean complexBeanByParameters(List<BasicBean> basicBeans) {
return new ComplexBean(basicBeans);
}
#Bean
public ComplexBean complexBeanByReferences() {
return new ComplexBean(Arrays.asList(basicBean1(), basicBean2()));
}
}
I can create two ComplexBeans using either parameter injection, which is elegant, but has shortcomings if a have a few other beans of BasicBean type and only want a few (the parameters can of course be of type BasicBean and enumerate by name the beans I'm interested of, but it could turn out to be a very long list, at least for arguments sake). In case I wish to reference the beans directly I might use the complexBeanByReferences style, which could be useful in case of ordering or some other consideration.
But say I want to use the complexBeanByReference style to reference the bean complexBeanByParameters, that is something along the line of:
#Bean
public ComplexBeanRegistry complexBeanRegistry() {
return new ComplexBeanRegistry(
Arrays.asList(
complexBeanByParameters(), // but this will not work!
complexBeanByReferences()
)
);
}
How would I reference complexBeanByParameters, without having to specify a list of dependencies to complexBeanRegistry? Which, the latter in all honesty should be completely oblivious of.
There is the option to just use
public ComplexBeanRegistry complexBeanRegistry(List<ComplexBeans> complexBeans) {...}
of course, but this might not be an option in certain cases, specifically when using the CacheConfigurer from spring-context. In this case the Java Config is intended to
create the beans
by implementing CacheConfigurer, override the default instances of the CacheManager and KeyGenerator beans.
The requirement to implement CacheConfigurer means I can't change the signature to use parameter injection.
So the question is, is there a way to reference complexBeanByParameters using the "direct" reference style?
Maybe you could reference it with separation by Qualifier:
#Bean
#Qualifier("complexBeanParam")
public ComplexBean complexBeanByParameters(List<BasicBean> basicBeans) {
return new ComplexBean(basicBeans);
}
#Bean
#Qualifier("complexBeanRef")
public ComplexBean complexBeanByReferences() {
return new ComplexBean(Arrays.asList(basicBean1(), basicBean2()));
}
and for example autowire:
#Autowired
#Qualifier("complexBeanParam")
private ComplexBean beanParam;
I'd like to write some base classes that should be picked by default to autowire with Spring. Only if these classes are extended, thus a custom implementation is provided for them, I want the custom implementation to be picked up, instead of the default one.
How can I achieve it when I don't want to make my default classes abstract (as the application should be able to run without custom implementations, just by the default ones)?
The the following example: I want to provide a basic handler for any errors. But this setup would only work if I make the BaseHandler abstract, which I don't want (as in this case I would force anyone using my library to implement the class).
#MessageEndpoint
public class BaseHandler {
#ServiceActivator(inputChannel = "errorChannel")
public A_Stadisdatensatz handle(Message<MessageHandlingException> message) {
process(message.getPayload());
}
/**
* Override to supply specific processing
*/
void process(Payload payload) {
//do some default processing
}
}
#MessageEndpoint
public class CustomHandler extends BaseHandler {
#Override
void process(Payload payload) {
//custom processing
}
}
If I run it this way, CustomHandler will never be picked up.
So, is it impossible?
I supose that you are using #Autowired to inject the dependencies. In that case you could use #Primary annotation to override defaults ones, ie
#Primary
#MessageEndpoint
public class CustomHandler extends BaseHandler {
#Override
void process(Payload payload) {
//custom processing
}
}
I want expose instances managed by an external framework to CDI applications using #Inject. These instances must be provided this other framework since their lifecycle is based on various caching strategies.
Ex: same instance is visible within same thread scope, might live across many request scopes, session scope is not applicable. Seems I need to define a new scope targeting these kind of instances?
What is the best way to do this? An extension, is it possible with producer methods?
I almost got it to work with producer methods using the following:
#Inject
#CustomInject
FwObject obj;
#Produces
#CustomInject
FwObject createConfig(InjectionPoint p) {
return (FwObject) ctx.get((Class<?>) p.getType());
}
But this force me to be explicit about the type produced which is not possible since there is no common framework interface.
Any help appreciated.
Maybe with producer methods, all depends on what you need, but an extension is probably the best way to go. If you need to go with a new scope (if you're using JSF the Conversation scope may work) you will certainly need to create an extension.
I think I solved it by creating a custom scope. The following article was really helpful:
http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
This is a very brief description of how I solved it.
Create custom scope annotation.
import javax.enterprise.context.NormalScope;
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
#NormalScope
public #interface CustomScope {
}
Create custom context.
import javax.enterprise.context.spi.Context;
public class CustomContext implements Context {
private MyFw myFw = .... ;
#Override
public Class<? extends Annotation> getScope() {
return CustomScope.class;
}
#Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public <T> T get(Contextual<T> contextual) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public boolean isActive() {
return true;
}
}
Create extension and register context.
import javax.enterprise.inject.spi.Extension;
public class CustomContextExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event, BeanManager manager) {
event.addContext(new CustomContext());
}
}
Register extension.
Add CustomContextExtension to META-INF/javax.enterprise.inject.spi.Extension
Add CustomScope to framework object.
#CustomScope
public class FwObject { ... }
Inject FwObject using #Inject where needed.
public class MyService {
#Inject
FwObject obj;
}