How to limit instantiation of class and methods in it -Java - java

#AllArgsConstructor(onConstructor = #__({ #Inject }))
public class TransactionManager {
private final TransactionHelper tnxHelper;
public void createTransactions(List<Details> details) {
tnxHelper.createTransactions(details);
}
}
#AllArgsConstructor(onConstructor = #__({ #Inject }))
public class TransactionHelper {
private final A a;
private final B b;
public void createTransactions(List<Details> details) {
//Some logic
}
}
So in the above code, I want TransactionManager to be the main class and every interactions related to Transaction should go via it, like createTransactions.
So how can i make TransactionHelper as hidden? So that no one can use this class apart from TransactionManager?
Also is there any way to only make createTransactions in TransactionHelper as hidden, rather than hiding the whole class.
Thank you in advance!!

Is the usage of Nested classes resolve your problem ?
https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
class TransactionManager {
// you cannot use the class TransactionHelper outside the TransactionManagerClass
// you need an instance of TransactionManager to have an instance of TransactionHelper
// so within static methods here you cant use it directly
private class TransactionHelper {
}
void dooo() {
TransactionHelper t = new TransactionHelper();
}
}

Related

Does a Java interface work different in Spring Boot? -- Is this Spring Wizardry or do I just not understand interfaces?

I'm working on an application that uses Spring Boot. In it, an interface is used in a way that I don't understand.
I've stripped down the code to the only parts that I think are relevant to the question.
A controller object is created.
It is told to process some stuff.
The controller tells an interface processor to do the work.
There is a processor that implements the interface processor.
It was my understanding that when using an interface you'd do something like: IProcessor iProcessor = new Processor();
In other words, assigning the interface an implementation. But in this sample program it seems the processor implementation is implicitly assigned, not in the code as far as I can tell. I'm trying to figure out if this is some Spring wizardry or if I'm just understanding interfaces wrong. There are four files that I have put in order of application flow.
#Component
public class DoStuff {
private ProcessorController PROCESSOR_CONTROLLER;
private OtherLayer OTHER_LAYER;
#Autowired
public DoStuff(ProcessorController processorController, OtherLayer otherLayer) {
this.PROCESSOR_CONTROLLER = processorController;
this.OTHER_LAYER = otherLayer;
}
public void execute() {
List<String> stuffToProcess = OTHER_LAYER.getStuffToProcess();
PsROCESSOR_CONTROLLER.process(stuffToProcess);
}
}
#Component
public class ProcessorController {
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(IProcessor iProcessor) {
this.IPROCESSOR = iProcessor;
}
public void process(List<String> stuffToProcess) {
stuffToProcess.forEach(t -> IPROCESSOR.process(t))
}
}
public interface IProcessor {
void process(String stuff);
}
#Component
public class Processor implements IProcessor {
#Override
public void process(String stuff) {
System.out.println(stuff);
}
}
If the ProcessorController class contained something like this:
So part of the ProcessorController class would look like this instead:
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(Processor Processor) {
this.IPROCESSOR = processor;
}
I think it would make sense since we've linked the interface with its implementation. But it isn't that way. So what is going on here?
Your understanding is correct
IProcessor iProcessor = new Processor();
The above way is correct way to assigning the implementation to Interface reference variable.This phenomena is known as loose coupling .Because if the method parameter type is of interface then it can be bind with multiple implementation based on requirement .
For Example we have
interface Test and Test1 and Test2 are its implementation classes
Then void method(Test test)
so now this method can bind with both Test1 and Test2 like method(Test1 obj) and method(Test2 obj)
But your controller is tightly coupled here not loosely coupled.Because Your constructor call is bind with Implementation class reference not interface.And if your project need tight coupling then there is no use to create class refrence of interface type rather you can create private final Processor PROCESSOR; instead of below code
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(Processor Processor) {
this.IPROCESSOR = processor;
}
It should be like
#Autowired
private final IProcessor IPROCESSOR;
or
private final IProcessor IPROCESSOR;
#Autowired
public ProcessorController(IProcessor Processor) {
this.IPROCESSOR = processor;
}

Is this an example of a 'Static Bean'?

public class SomeClass {
private static final int num = 432;
#Bean
public int getNum(){
return num;
}
}
or would the method signature need to actually have the static keyword ?
I am not entirely sure about what you mean about a static Bean, Beans are instances in runtime.
If you mean Singleton, meaning that the bean would be created on application start and destroyed in application end.
Then by default, every Bean is #Bean(scope=DefaultScopes.SINGLETON), if you want a bean to be created every new usage of it, you can define it as #Bean(scope=DefaultScopes.PROTOTYPE)
Take a look at the doc: https://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
My understanding of a static bean would be different. As an example, take a look at the EventPublisherHolder class from Eclipse Hawkbit:
public final class EventPublisherHolder {
private static final EventPublisherHolder SINGLETON = new EventPublisherHolder();
#Autowired
private ApplicationEventPublisher eventPublisher;
public static EventPublisherHolder getInstance() {
return SINGLETON;
}
public ApplicationEventPublisher getEventPublisher() {
return eventPublisher;
}
...
}
The way the ApplicationEventPublisher is injected into the EventPublisherHolder is through Spring magic
#Bean
EventPublisherHolder eventBusHolder() {
return EventPublisherHolder.getInstance();
}
The EventPublisherHolder class makes it easier to get the ApplicationEventPublisher statically.
As an example, take a look at the way this class is intended to be used:
From JpaAction class:
#Override
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new ActionCreatedEvent(...));
}
In this sense, you can consider the EventPublisherHolder bean to be a static bean.

Spring Boot: how to inject dependencies into a class called by a library?

I'm using Kinesis Client Library (KCL) and Spring boot. To use KCL, I have to implement a class (I named it RecordProcessor) for interface IRecordProcessor. And KCL will call this class and process records from kinesis. But when I tried to use dependency injection, I found it was not succeeded.
Here's the snippet for RecordProcessor:
#Component
public class RecordProcessor implements IRecordProcessor {
#Autowired
private SingleRecordProcessor singleRecordProcessor;
#Override
public void initialize(String shardId) {
...
}
#Override
public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
...
}
}
I use Class SingleRecordProcessor to process single each record from kinesis. And this is my SingleRecordProcessor class snippet:
#Component
public class SingleRecordProcessor {
private Parser parser;
private Map<String, Table> tables;
public SingleRecordProcessor() {
}
#Autowired
private void setParser(Parser parser) {
this.parser = parser;
}
#Autowired
private void setTables(Map<String, Table> tables) {
this.tables = tables;
}
public void process(String record) {
...
}
}
I want to let spring framework automatically inject the SingleRecordProcessor instance into the class and use it. But I found that the field singleRecordProcessor is null.
Any idea why the dependency injection is failed? Or is it impossible to inject dependencies into a class which is called by other framework (in this case it's KCL)? Any suggestions will be appreciated! Really need some help please!!
[UPDATE]:
Sorry for not expressing the error clearly. The error was NullPointerException. I tried to inject singleRecordProcessor and call method process() on it. I think the injection was not successful so the instance singleRecordProcessor is null and there comes the NullPointerException.
More information is as follows:
I have a major class called Application
#SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./app.pid"));
ConfigurableApplicationContext ctx = application.run(args);
}
}
And I have the MainProcessor class which will call KCL.
#Service
public final class MainProcessor {
#EventListener(ApplicationReadyEvent.class)
public static void startConsumer() throws Exception {
init();
IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
Worker worker = new Worker(recordProcessorFactory, kinesisClientLibConfiguration);
...
worker.run(); // this line will call KCL library and eventually call ProcessorRecord class.
}
}
[UPDATE2]
RecordProcessorFactory only has one method like this
#Component
public class RecordProcessorFactory implements IRecordProcessorFactory {
#Autowired
RecordProcessor recordProcessor;
#Override
public IRecordProcessor createProcessor() {
return recordProcessor;
}
}
It creates a new RecordProcessor instance for KCL to use it.
You should autowire an instance of this into your MainProcessor:
#Component
public class RecordProcessorFactory {
#Lookup IRecordProcessor createProcessor() { return null; }
}
Spring will instantiate a RecordProcessorFactory for you, and replace the implementation of createProcessor() in it with one that will return a new IRecordProcessor each time it's called. Both the factory and the processors will be Spring beans - which is what you want.

Spring injected beans null in nested class

I have a class with 2 static nested classes that do the same operation on 2 different generic types.
I exposed the 2 classes as beans and added #Autowired for the constructors as I usually do.
Here is the basic setup
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
#Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
#Service
public static class ImplA extends Parent<A> {
#Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
#Service
public static class ImplB extends Parent<B> {
#Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
And in another class I have
#Service
public class Doer {
private final List<MyInterface<A>> aImpls;
#Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
When I run the app, everything appears to be injected correctly and when I put a breakpoint in the ImplA and ImplB constructors, I have a not-null value for "service". I also have an ImplA bean in the aImpls list in Doer.
When I call doImportantThingWithA(a) however, "service" is null inside ImplA and I obviously die.
I'm not sure how this is possible because:
I see a nonnull value in my constructors for service which is a final field.
If spring is injecting ImplA and ImplB into another class, it should already have either injected a Service into ImplA or ImplB, or thrown an exception on bean initialization. I have nothing set to lazily load and all bean dependencies are required.
The reason for the nested classes is because the only thing that changes between the 2 implementations is the map() function. Trying to avoid extra classes for 1 line of varying code.
More info:
When I add a breakpoint in Parent.doInterfaceThing(), if I add a watch on "service" I get null as the value. If I add a getService() method, and then call getService() instead of referring directly to this.service, I get the correct bean for service. I don't know the implications of this but something seems weird with the proxying.
It looks like what is causing the issue is Parent.doInterfaceThing();
If I remove final from the method signature, "service" field is correctly populated and the code works as expected.
I don't understand at all why changing a method signature affects the injected value of final fields in my class... but it works now.
What I meant with my "use mappers" comment was something like this:
class MyInterfaceImpl implements MyInterface {
#Autowired
private final Service service;
#Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
#Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
#Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
This does have a few more lines than the original, but not much; however, you do have a better Separation of Concern. I do wonder how autowiring works in your code with the generics, it does look as if that might cause problems.
Your client would look like this:
#Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
#Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}

Shared prototype beans in Spring

I need to create multiple instances of a spring bean (let's call it MainPrototypeBean), which I can do with the prototype scope. It depends on some other beans, and I want to create new instances of them each time the main bean is created. However, there is a shared dependency between some of the beans, let's call it SharedPrototypeBean. How do I inject the same instance of SharedPrototypeBean in each of the dependent beans, while also creating a new instance for each MainPrototypeBean?
I'm looking into implementing a custom scope, but I'm hoping to find a cleaner way. Making any of the beans singletons is not an option, as they need to be isolated between different instances of MainPrototypeBean.
Here's an example of what I'm trying to do:
#SpringBootApplication
public class DIDemo {
public static void main(String[]args){
ConfigurableApplicationContext context = SpringApplication.run(DIDemo.class, args);
context.getBean(MainPrototypeBean.class);
}
#Component #Scope("prototype") static class SharedPrototypeBean {}
#Component #Scope("prototype") static class FirstPrototypeBean {
#Autowired SharedPrototypeBean shared;
#PostConstruct public void init() {
System.out.println("FirstPrototypeBean.init() with shared " + shared);
}
}
#Component #Scope("prototype") static class SecondPrototypeBean {
#Autowired SharedPrototypeBean shared;
#PostConstruct public void init() {
System.out.println("SecondPrototypeBean.init() with shared " + shared);
}
}
#Component #Scope("prototype") static class MainPrototypeBean {
#Autowired FirstPrototypeBean first;
#Autowired SecondPrototypeBean second;
}
}
And the output of executing it is:
FirstPrototypeBean.init() with shared DIDemo$SharedPrototypeBean#1b84f475
SecondPrototypeBean.init() with shared DIDemo$SharedPrototypeBean#539d019
You can use the FactoryBean for complex construction logic. Implement its abstract subclass AbstractFactoryBean for creating a MainPrototypeBean, and inject all three dependent beans into it. You can then wire them together in the createInstance method.
The FactoryBean implementation:
public class MainFactoryBean extends AbstractFactoryBean<MainPrototypeBean> implements FactoryBean<MainPrototypeBean> {
private FirstPrototypeBean firstPrototype;
private SecondPrototypeBean secondPrototpye;
private SharedPrototypeBean sharedPrototype;
public MainFactoryBean(FirstPrototypeBean firstPrototype, SecondPrototypeBean secondPrototype, SharedPrototypeBean sharedPrototype) {
this.firstPrototype = firstPrototype;
this.secondPrototpye = secondPrototype;
this.sharedPrototype = sharedPrototype;
}
#Override
protected MainPrototypeBean createInstance() throws Exception {
MainPrototypeBean mainPrototype = new MainPrototypeBean();
firstPrototype.setSharedPrototypeBean(sharedPrototype);
secondPrototpye.setSharedPrototypeBean(sharedPrototype);
mainPrototype.first = firstPrototype;
mainPrototype.second = secondPrototpye;
//call post construct methods on first and second prototype beans manually
firstPrototype.init();
secondPrototpye.init();
return mainPrototype;
}
#Override
public Class<?> getObjectType() {
return MainPrototypeBean.class;
}
}
Note: sharedPrototype is injected after the post-construct phase in the lifecycle of the first and second prototype. So, if you have post-construction logic in these beans that require the sharedPrototype, you need to manually call the init-method when creating the MainPrototypeBean.
Your annotation - configuration changes as as a consequence. The sharedPrototype attributes are no longer autowired (they are set inside FactoryBean), and MainPrototypeBean is not annotated anymore. Instead you need to create the MainFactoryBean.
#Configuration
public class JavaConfig {
//method name is the name refers to MainPrototypeBean, not to the factory
#Bean
#Scope("prototype")
public MainFactoryBean mainPrototypeBean(FirstPrototypeBean firstPrototype, SecondPrototypeBean secondPrototype, SharedPrototypeBean sharedPrototype) {
return new MainFactoryBean(firstPrototype, secondPrototype, sharedPrototype);
}
//Annotations are not needed anymore
static class MainPrototypeBean {
FirstPrototypeBean first;
SecondPrototypeBean second;
}
#Component
#Scope("prototype")
static class SharedPrototypeBean {
}
#Component
#Scope("prototype")
static class FirstPrototypeBean {
private SharedPrototypeBean shared;
//no autowiring required
public void setSharedPrototypeBean(SharedPrototypeBean shared) {
this.shared = shared;
}
#PostConstruct
public void init() {//reference to shared will be null in post construction phase
System.out.println("FirstPrototypeBean.init() with shared " + shared);
}
}
#Component
#Scope("prototype")
static class SecondPrototypeBean {
private SharedPrototypeBean shared;
public void setSharedPrototypeBean(SharedPrototypeBean shared) {
this.shared = shared;
}
#PostConstruct
public void init() {
System.out.println("SecondPrototypeBean.init() with shared " + shared);
}
}
}
After reading the comments and the other answer, I realized that the design is indeed too complex. I made SharedPrototypeBean, FirstPrototypeBean and SecondPrototypeBean regular POJOs, not managed by Spring. I then create all of the objects in a #Bean annotated method.
#Bean
public MainPrototypeBean mainPrototypeBean() {
Shared shared = new Shared();
First first = new First(shared);
Second second = new Second(shared);
return new MainPrototypeBean(first, second);
}

Categories