I have a filter service whose methods are profiled through the aspect. As an example I will give you a piece of code where I have a problem
#Service
public class FilterService extends AbstractService {
private static final Logger log = LoggerFactory.getLogger(FilterService.class);
#Autowired
//Proxy to profiling class
private FilterService self;
private final ItemsRepository itemsRepository;
private final Map<String, EnumFilter> enumFilters;
public FilterService(ReadWriteLock readWriteLock,
ItemsRepository itemsRepository,
CategoryRepository categoryRepository, ItemsMapper itemsMapper,
CharacteristicsRepository characteristicsRepository,
List<EnumFilter> enumFilters) {
super(readWriteLock.readLock());
this.itemsRepository = itemsRepository;
this.enumFilters = enumFilters.stream().collect(Collectors.toMap(EnumFilter::getId, y -> y));
}
#Profileable
public ItemsViewShared filterItems(#Nullable String categoryId,
#NotNull Set<String> ids,
#NotNull Lang lang,
#NotNull SortType sortType,
#NotNull FilterInfo filterInfo) {
try {
this.readLock.lock();
final ItemsViewShared itemsViewResponse = new ItemsViewShared(); //in this line inspector show this = FilterService
List<Filter> allFilters = self.initNonSpecificFilters(lang, filterInfo); //problem is here
//some code...
#Profileable
private List<Filter> initNonSpecificFilters(#NotNull Lang lang, #NotNull FilterInfo filterInfo) {
final List<NumericFilter> allNumericNonSpecific = NumericFilter.getAllNonSpecific(lang, filterInfo);
//in this line enumFilters - null
final List<EnumOptionFilter> allEnumNonSpecific = enumFilters.values().stream()
.flatMap(x -> x.getAllOptions(lang, filterInfo).stream())
.collect(Collectors.toList());
As i know, by default, If the class does not inherit the interface with at least one method, the CGlib proxy will be used and Cglib works through inheritance.
The problem is this: when I call the filterItems method from the controller, the debugger shows in this method that this - FilterService.
Further in this method another method of this class which too should be profiled is caused. In order for the proxy to work, I need self autowired. After that I called my method via self.initNonSpecificFilters and in the debugger I already see that this - FilterService$$EnhancerBySpringCGLIB and all my variables in my class is null, so I get null pointer exception.
Why so, if CGLIb seems to work through inheritance? And why in the first method(filterItems) this - was a class without CGlib, but when you call from it another method (filterItems -> initNotSpecificFilters), cglib already appears.
The problem is that dynamic proxies, no matter whether JDK interface proxies or CGLIB class proxies, only inherit
public methods (JDK, CGLIB) or
protected and package-scoped methods (CGLIB only).
Furthermore, proxies do not inherit any instance variable values because that is not their purpose, they only wrap around methods and call the originals plus maybe before and after aspect advices or interceptors.
Now your situation is as follows:
Your method initNonSpecificFilters(..) is private. I.e. if you call it upon self, you will actually still call the original method (because it is not wrapped), but the proxy's members have no values, of course.
BTW, the fact that the method is private is also why the Spring AOP aspect would not kick in for that method if you had a pointcut targeting it (with AspectJ it would be different).
Search the Spring manual for the term self-invocation, the behaviour is nicely documented.
The solution to your problem is to make the method non-private.
Related
I'm searching for a elegant way, to define fields in standard spring-service.
Without lombok our service looks like this:
#Service
public class ServiceA {
private final String applicationName;
private final SpecialHandler specialHandler;
private final ServiceC serviceC;
public ServiceA(final ConfigBean config,
final ServiceB serviceB,
final ServiceC serviceC) {
this.applicationName = config.getBaseConfig().getApplicationInfo().getName();
this.specialHander = serviceB.getSpecialForAppName(this.applicationName);
// PROBLEM: each direct dependency forces us to write more and more manual code
this.serviceC = serviceC;
}
}
Now, our team want to use the lombok-constructor only (so we can easily add other services). The service above will now look this:
#Service
#RequiredArgsConstructor
public class ServiceA {
private final ServiceC service;
// ^- with lombok, this is very pretty and simpel
private final ConfigBean config;
private final SpecialHandler specialHandler;
// ^- PROBLEM: these fields only used in the "createFields()"-method
// can we inline them somehow?
private String applicationName;
private SpecialHandler specialHanlder;
// ^- PROBLEM: these fields are not final anymore
// can we "make fields final again"?
#PostConstruct
public void createFields() { // maybe we can put parameters to the post-construct?
this.applicationName = this.config.getBaseConfig().getApplicationInfo().getName();
this.specialHander = this.serviceB.getSpecialForAppName(this.applicationName);
}
}
Question
How can I solve the issues (mentioned in the sourceCode-comments)?
Footnote
I saw this "problem" in many projects. The variants, which I mentioned above, are the only solutions I saw yet. Both solutions getting more ugly when raising the number of fields.
Lombok only writes boilerplate code for you. It means that, as soon as you have anything non trivial to do, you can't use it anymore.
So if you want to keep your fields computed in the constructor final, you will have to write the constructor by hand.
As far as I know, a #PostConstruct method can't accept any parameter either.
There are two possibles tracks to follow:
you can certainly use field-based or setter-based injection, using #Autowired annotation.
Pass an already constructed SpecialHandler to your service. You can do so, , rather than using #Service annotation, by creating it in a #Bean method inside a #Configuration class for example.
So, working with Spring and transactional management I noticied something weird today,
public abstract class Processer<T> {
final Class<T> received;
#Autowired
private ObjectMapper mapper;
protected abstract void handle(T request);
// transactional on final abstract method, here is the issue,
// when I remove final it works, but I want final
#Transactional
final public void safeHandle(String... args) {
T request = objectMapper.map(args[1);
handle(request);
}
}
One of my extended sub classes,
#Component("ack-processor")
public class AckProcessor extends Processor<AckModel> {
// doing this to register the received <T> object in the abstract class
public AckProcessor() {
super(AckModel.class)
}
protected void handle(AckModel request) { // some transactional statements}
}
Now when I call from caller method
// below is mocked, but assume we have a genric class that picks up the bean by component name, and could inject this abstract properly
// usually something like more than 1 of this processor extensions is present in my scenario
Processor<T> processor = context.getBean(AckProcessor.class);
processor.handle(...);
// here we get update/delete cannot be performed - javax.persistence.TransactionalRequired exception
My question is, when I annotate the abstract class final method with Transactional, the transactional is not started, but weird thing, my autowired objectMapper and received object are both being set as null, though the component was picked based on component name wiring "ack-processor", then when I remove the final signature and left the #Transactional it seems to work, both the transactional is enabled, and the object mapper is being set properly, but I lose the final signature. Which I don't want, I am not sure the docs explain why final methods cannot be transactional.
The reason is, in my real production scenario, the abstract class is not only with one generic <T>, it has <T,R> and it does a bunch of process, which is boiler plate on these generics and based on certain criteria passed in the args it calls the sub classes abstract method like, say, there is bunch of abstract methods, successHandle(), failuerHandle(), onHoldHandle() etc, so I need to imply my abstarct class method as final, as I don't want other classes to implement this, I don't want anyone implementing to mess up this handle boiler plate logic.
I have following Java class:
public class FooServiceImpl {
private BarService barService;
public String generateFoo() {
String barValue = barService.generateBar();
return customFoo() + barValue;
}
public String customFoo() {
return "abc";
}
}
And here is exemplary Spock test method:
def "generate foo bar"() {
setup:
def barService = Mock(BarService) {
generateBar() >> "Bar"
}
FooServiceImpl spyFooService =
Spy(FooServiceImpl, constructorArgs: [[barService: barService]])
spyFooService.customFoo() >> "foo"
when:
def fooValue = spyFooService.generateFoo()
then:
fooValue == "fooBar"
}
I try to create a Spy object for FooServiceImpl class but I get following error:
org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack:
No such property: barService for class:
com.foo.FooServiceImpl$$EnhancerByCGL`
I can't add a constructor to FooServiceImpl or setter for BarService, so I want to use map constructor. Is this possible?
Note: according to this issue it should work
The easiest solution in your case would be to make this field protected instead of private. When you create a spy object from a class, CGLIB is involved and it creates as subclass from the class you are trying to create spy from - com.foo.FooServiceImpl$$EnhancerByCGL in your case. The thing is that the field you are trying to modify is a private field and according to regular subclassing strategy in Java, private field does not get inherited in child class. That is why field barService does not exist in spy object
ATTENTION: IntelliJ's debugger may tell you that barService is present in this spyFromService instance, however this is IDE's bug - if you list all available fields from spyFromService.class.fields or spyFromService.class.declaredFields you wont find barService field here.
Another problem is that when CGLIB gets involved in object creation process it also gets involved if it comes to invoking methods. This is why adding dynamic fields to a class or instance via Groovy's metaprogramming features wont work. Otherwise you would be able to do things like:
spyFromService.metaClass.barService = barService
or
spyFromService.class.metaClass.barService = barService
Alternatively you could get rid of spy object and use a real instance in your test. Then
FooServiceImpl spyFromService = new FooServiceImpl()
spyFromService.#barService = barService
will work. However you won't be able to stub existing customFoo() method and you will have to rely on what its real implementation returns.
My class depends on some services which needs to take few parameters and then make network call, currently I am passing those parameters and then creating those services via a factory injected into my class. I need to inject those services as a dependency instead, I know that I can create providers for them but in most of the examples I see that the providers are often bound to the fixed values like serveraddres etc. but I need to give then values during run time.
Below is my example code:
public SomeClass {
private final SomeFactory someFactory;
#Inject
SomeClass(SomeFactory factory) {
someFactory = factory;
}
public Foo getFoo(String fooId) {
FooService fooService = someFactory.getFooService(fooId);
return fooService.getFoo();
}
}
What I need to do is:
public SomeClass {
private final FooService fooService;
#Inject
SomeClass(FooService fooService) {
this.fooService = fooService;
}
public Foo getFoo(String fooId) {
return fooService.getFoo();
}
}
Update 1
Making the use case more clear:
#Provides
#RequestScoped
public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
return new SomeService.Builder()
.withApplicationName("Foo")
.setCode(code)
.build();
}
Here, code can be null by default and when needed I can give some value in it.
Can I somehow pass arguments to the provider before its created?
If you have a binding for your value (here, code is a String without a binding annotation), then your Update 1 is exactly what the code would look like.
In practice, there are a few differences:
Constants like int and String values are generally annotated with a binding annotation, either #Named or a custom annotation.
If you need to inject a value into an object graph after Guice initialization, but have a deep enough object graph that dependency injection is still a good idea, you can create a child injector. This way you can make a #Named("code") String accessible within one action or object, but not across your entire Guice application.
If your value for code is dynamic enough that it can't be provided through Guice as a key of its own, then you'll have to pass it in using a factory of some sort. For a Builder-based object, I'd say that your SomeFactory implementation is the best that I would come up with in your case.
If you don't need to use a Builder, and can let Guice create the object based on your fields or constructor parameters, you can code-generate a Factory.
Guice can generate a factory for you through FactoryModuleBuilder, in a feature known as "assisted injection".
Google's other tool, AutoFactory, will code-generate a factory implementation that works in both Guice and Dagger. (It's bundled as "Auto", which includes a model object generator called AutoValue that also generates annotation implementations.)
I put a small demonstration of a child injector and assisted injection in my other SO answer here.
The best approach here is to parameterize the module and pass the parameter through to a provider that you create at runtime:
public class MyModule extends AbstractModule {
private final String code;
public MyModule(String code) {
this.code = code;
}
#Override public void configure() {
Provider<Dep1> depProvider = getProvider(Dep1.class);
bind(SomeService.class)
.toProvider(() -> new SomeService.Builder()
.withApplicationName("Foo")
.withDep(depProvider.get())
.setCode(code)
.build())
.in(RequestScoped.class);
}
}
I'm trying to mock a class that looks like below
public class MessageContainer {
private final MessageChain[] messages;
MessageContainer(final int numOfMessages, final MessageManagerImpl manager, final Object someOtherStuff) {
messages = new MessageChain[numOfMessages]
// do other stuff
}
public void foo(final int index) {
// do something
messages[index] = getActiveMessage();
}
}
My test code would be as followed:
#Test
public void testFoo() {
MessageContainer messageContainer = Mockito.mock(MessageContainer.class);
Mockito.doCallRealMethod().when(messageContainer).foo(anyIndex);
}
I got a NullPointerException since 'messages' is null. I tried to inject the mock by using #InjectMocks, however this case is not supported since not every parameters of the constructor are declared as members.
I also tried to set the 'messages' field by using WhiteBox
Whitebox.setInternalState(messageContainer, MessageChain[].class, PowerMockito.mock(MessageChain[].class));
but I got a compile error since setInternalState only supports (Object, Object, Object) and not Object[].
Is there any possible way to mock a private final field?
Thank you guys in advance.
Based on your edits and comments, I would say mocking this class and verifying the method was invoked is sufficient.
If it is third-party code, you should rely only on its method signature, which comprises the class's public API. Otherwise you are coupling your tests too tightly to something you have no control over. What do you do when they decide to use a Collection instead of an array?
Simply write:
MessageContainer container = mock(MessageContainer.class);
//Your code here...
verify(container).foo(obj);