In the first Version of my program, I load MainScreen without problems on this way:
public class MyUI extends UI {
public void showMainView() {
addStyleName(ValoTheme.UI_WITH_MENU);
setContent(new MainScreen(MyUI.this));
mainScreen.setUI(MyUI.this);
}
public static MyUI get() {
return (MyUI) UI.getCurrent();
}
}
But now, I have changed it to:
#SpringUI
#Viewport("user-scalable=no,initial-scale=1.0")
#Theme("mytheme")
public class MyUI extends UI {
#Autowired
MainScreen mainScreen;
public void showMainView() {
addStyleName(ValoTheme.UI_WITH_MENU);
setContent(mainScreen);
getNavigator().navigateTo(getNavigator().getState());
}
public static MyUI get() {
return (MyUI) UI.getCurrent();
}
}
To get MainScreen via #Autowired, I had to clear the Constructor of MainScreen, but I don't know how to get now the UI I need for navigator.
I just get null in both ways.
#Component
#UIScope
public class MainScreen extends HorizontalLayout {
public MainScreen() {
UI ui = UI.getCurrent(); // is null
MyUI ui2 = MyUI.get(); // is null
CssLayout viewContainer = new CssLayout();
viewContainer.addStyleName("valo-content");
viewContainer.setSizeFull();
final Navigator navigator = new Navigator(ui, viewContainer);
// ...
}
I'm not familiar with all the frameworks you tagged. I'm going to address what I believe to be a logical error or possibly an incorrect design.
If you #Autowire the MainScreen into the UI you're allowing spring to guarantee whatever that is to be there. If you look at it using the preferred constructor injection it might be more obvious.
public class MyUI extends UI {
private MainScreen mainScreen;
#Autowired
public MyUI (MainScreen mainScreen) {
this.mainScreen = mainScreen;
}
}
MainScreen has already been instantiated at that point and could very well be in other parts of the code already so the mainScreen constructor shouldn't be dependent on MyUI.
How you deal with it is depends on what the desired behavior and relationship is. If you're needing the UI class in mainScreen but can't depend on it being available then you'll have to pass it in from the UI class itself (mainScreen.foo(this);).
Related
I have an abstract service class.
abstract class AbstractService<T> {
public void saveNew(T entity) {
}
}
And I have two more abstract classes extends AbstractService and implement a shared interface.
abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {
}
abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {
}
Now I want to validate the entity argument on these two extending services' saveNew(T) method.
How can I define a #Pointcut and (or) an #Around for following conditions?
extends the AbstractService class
implements the SharedInterface interface
you can use within as following:
within(com.somepackage.Super+)
where com.somepackage.Super is the fully qualified base class name and + means "all subclasses". Other pointcut is
execution(* com.somepackage.Super+.*(..))
R.G's solution has a few disadvantages:
The pointcut matches too many joinpoints.
Thus it needs reflection in order to filter out the unnecessary ones.
I am going to show you a stand-alone AspectJ solution (no Spring, I am not a Spring user), but the aspect would look just the same in Spring, you only need to make it a #Component or declare a #Bean factory in your configuration. But the same applies to all the classes you want to intercept, of course.
Because I prefer a full MCVE with all necessary dependency classes in order for you to be able to copy, compile and run it, and because I also added negative test cases (sub-classes only extending the abstract base class or only implementing the interface), this is a lot of code. So please bear with me:
Abstract classes, interface and helper classes:
package de.scrum_master.app;
public abstract class AbstractService<T> {
public void saveNew(T entity) {
System.out.println("Saving new entity " + entity);
}
}
package de.scrum_master.app;
public class Some2 {}
package de.scrum_master.app;
public class Some3 {}
package de.scrum_master.app;
public abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public interface SharedInterface {
void doSomething();
}
Driver application (AspectJ + POJOs, not Spring):
This driver class contains some static inner classes subclassing the given base classes and/or implementing the shared interface. Two are used for positive tests (should be intercepted), two for negative tests (should not be intercepted). Each class also contains an additional method as another negative test case which should not be matched - better safe than sorry.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
// Should be intercepted
InterceptMe1 interceptMe1 = new InterceptMe1();
interceptMe1.saveNew(new Some2());
interceptMe1.doSomething();
interceptMe1.additional();
printSeparator();
// Should be intercepted
InterceptMe2 interceptMe2 = new InterceptMe2();
interceptMe2.saveNew(new Some3());
interceptMe2.doSomething();
interceptMe2.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe1 dontInterceptMe1 = new DontInterceptMe1();
dontInterceptMe1.saveNew(new Some2());
dontInterceptMe1.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe2 dontInterceptMe2 = new DontInterceptMe2();
dontInterceptMe2.additional();
printSeparator();
}
private static void printSeparator() {
System.out.println("\n----------------------------------------\n");
}
static class InterceptMe1 extends MoreAbstractService2<Some2> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService2<Some2>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService2<Some2>");
}
}
static class InterceptMe2 extends MoreAbstractService3<Some3> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService3<Some3>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService3<Some3>");
}
}
static class DontInterceptMe1 extends AbstractService<Some2> {
public void additional() {
System.out.println("Additional method in AbstractService<Some2>");
}
}
static class DontInterceptMe2 implements SharedInterface {
#Override
public void doSomething() {
System.out.println("Doing something in SharedInterface"); }
public void additional() {
System.out.println("Additional method in SharedInterface");
}
}
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class EntityValidationAspect {
#Before(
"execution(* saveNew(*)) && " +
"args(entity) && " +
"target(de.scrum_master.app.SharedInterface) && " +
"target(de.scrum_master.app.AbstractService)"
)
public void validateEntity(JoinPoint thisJoinPoint, Object entity) {
System.out.println("-> Pre-save entity validation: " + entity);
}
}
As you can see, the aspect uses two target() pointcuts which must both match. It also specifically targets any saveNew method with a single argument saveNew(*), binding that argument as an advice method parameter via args().
For demonstration's sake I do not validate anything (I don't know how you want to do that) but just print the entity. Thus, a #Before advice is sufficient. If in case of negative validation you want to throw an exception, this advice type is also okay. If you need to do more, such as manipulate the entity's state or replace it before passing it on to the target method, call an alternative target method instead or none at all, return a specific result (in case of non-void methods, here not applicable), handle exceptions from the target method etc., you ought to use an #Around advice instead.
Console log:
-> Pre-save entity validation: de.scrum_master.app.Some2#28a418fc
Saving new entity de.scrum_master.app.Some2#28a418fc
Doing something in MoreAbstractService2<Some2>
Additional method in MoreAbstractService2<Some2>
----------------------------------------
-> Pre-save entity validation: de.scrum_master.app.Some3#5305068a
Saving new entity de.scrum_master.app.Some3#5305068a
Doing something in MoreAbstractService3<Some3>
Additional method in MoreAbstractService3<Some3>
----------------------------------------
Saving new entity de.scrum_master.app.Some2#1f32e575
Additional method in AbstractService<Some2>
----------------------------------------
Additional method in SharedInterface
----------------------------------------
Et voilĂ - the aspect does exactly what you asked for, as far as I understand your requirement. :-) More specifically, it does not get triggered in the third case when saveNew is being called, but the class does not implement the interface.
Following code can be used for the validation mentioned.
The point cut is to intercept on the execution of a specific method for the subclasses of AbstractService and the code logic is to only validate if SharedInterface is a superinterface of the target bean.
The use of isAssignableFrom() is required as the interfaces proxied by the AOP proxy does not include SharedInterface. As per my understanding , a pointcut expression to match the second criteria will not be possible for the same reason and hence handled the requirement in the code logic.
Hope this helps
#Aspect
#Component
public class ValidationAspect {
#Pointcut("execution(* package.to.AbstractService+.saveNew(..))")
public void isAbstractServiceType() {
}
#Around("isAbstractServiceType() && args(entity) && target(bean)")
public void validateEntityArugments(ProceedingJoinPoint pjp, Object entity, Object bean) throws Throwable {
if (SharedInterface.class.isAssignableFrom(bean.getClass())) {
System.out.println(entity);
// ..validate
}
pjp.proceed();
}
}
I have the following:
#Configuration
public class ConsorsCrucibleTestsConfiguration {
public AtomicReference<Functions.FailableFunction<MergedContextConfiguration, ApplicationContext, Exception>> crucibleApplicationContextFunction() {
return new AtomicReference<>(null);
}
public class SettableApplicationContextLoader extends SpringBootContextLoader {
public class SettableApplicationContextLoader extends SpringBootContextLoader {
#Autowired
private AtomicReference<FailableFunction<MergedContextConfiguration, ApplicationContext, Exception>> applicationContextFunction;
// use `applicationContextFunction`
}
#SpringBootTest
#ContextConfiguration(loader = SettableApplicationContextLoader.class)
class CucumberStepsBase {
}
But when it's time to use applicationContextFunction, it's null. Is there a way to have it injected into the context loader?
A context loader creation happens before the dependency injection occurs in your application. If you use breakpoints, you will see that you pass into your SettableApplicationContextLoader before passing through your ConsorsCrucibleTestsConfiguration bean method.
What are you trying to achieve exactly ? Maybe this could be a better start.
In my application, I have two classes having the same name, but of course in different packages.
Both classes need to be injected in the application; Unfortunately, I get the following error message:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'myFeature' for bean class [org.pmesmeur.springboot.training.service.feature2.MyFeature] conflicts with existing, non-compatible bean definition of same name and class [org.pmesmeur.springboot.training.service.feature1.MyFeature]
My issue can be reproduced by the following sample:
#Component
#EnableConfigurationProperties(ServiceProperties.class)
public class MyService implements IService {
private final ServiceProperties serviceProperties;
private final IProvider provider;
private final org.pmesmeur.springboot.training.service.feature1.IMyFeature f1;
private final org.pmesmeur.springboot.training.service.feature2.IMyFeature f2;
#Autowired
public MyService(ServiceProperties serviceProperties,
IProvider provider,
org.pmesmeur.springboot.training.service.feature1.IMyFeature f1,
org.pmesmeur.springboot.training.service.feature2.IMyFeature f2) {
this.serviceProperties = serviceProperties;
this.provider = provider;
this.f1 = f1;
this.f2 = f2;
}
...
package org.pmesmeur.springboot.training.service.feature1;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature1;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
package org.pmesmeur.springboot.training.service.feature2;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature2;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
If I use different names for my classes MyFeature, my problem disappears!!!
I am used to work with Guice and this framework does not have this kind of problem/limitation
It seems that the spring dependencies injection framework uses only
the class-name instead of package-name + class-name in order to
select its classes.
In "real-life" I have this problem with a far-bigger project and I would strongly prefer not to have to rename my classes: can anyone help me?
One last point, I would prefer to avoid "tricks" such as using
#Qualifier(value = "ABC") when injecting my classes: in my sample,
there should be no ambiguity for finding the correct instance of
MyFeature as they do not implement the same interface
Simply re-implementing BeanNameGenerator adds a new problem for beans declared/instantiated by names
#Component("HelloWorld")
class MyComponent implements IComponent {
...
}
#Qualifier(value = "HelloWorld") IComponent component
I solved this issue by extending AnnotationBeanNameGenerator and redefining method buildDefaultBeanName()
static class BeanNameGeneratorIncludingPackageName extends AnnotationBeanNameGenerator {
public BeanNameGeneratorIncludingPackageName() {
}
#Override
public String buildDefaultBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
return beanDefinition.getBeanClassName();
}
}
You can assigna a value for each component e.g. #Component(value="someBean") and then inject it with #Qualifier e.g.
#Autowired
public SomeService(#Qualifier("someBean") Some s){
//....
}
Spring provides autowire by type and name. Your classname are same. By default spring considers only className not package. But you can override this behaviour by defining custom implementation of BeanNameGenerator interface in which you can generate name using both package and name. I am not providing code solution because i think you should explore more on this.
You can do something like this;
in package a
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
in package b
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
and in some config class;
#Configuration
public class Configuration {
#Bean
public a.MyFeature f1() {
return new a.MyFeature();
}
#Bean
public b.MyFeature f2() {
return new b.MyFeature();
}
}
Then you can autowire them with names f1 and f2, that are the names of their respective bean constructor methods.
You can do the similar thing with #Component("f1") &
#Component("f2")
Even though different interfaces are implemented and are in different packages, identical bean name causes this trouble, and you have to utilize some sort of custom naming to distinguish. Utilizing some custom Spring logic would be way too ugly compared to what you'd do with above solutions.
I want to access a getter from a Class that uses Vaadins #Route annotation.
Instantiating the class does not work and autowiring neither
This is my entry point. From here Id like to call the getter from the button in the next class to add the actionlistener(clicklistener) to further utilize its data in a small swing window
#SpringBootApplication
public class App
{
#Autowired
Main main;
public static void main( String[] args )
{
SpringApplicationBuilder builder = new SpringApplicationBuilder(App.class);
builder.headless(false);
ConfigurableApplicationContext configurableApplicationContext = builder.run(args);
View view = new View();
}
}
This is the class which implements Vaadin. Here is the getter I want to call
#Route("index")
public class Main extends VerticalLayout {
VerticalLayout buttons = new VerticalLayout();
TextField field = new TextField();
Button button = new Button("commit change");
public Main() {
button.addClickListener(buttonClickEvent -> {
if (StringUtils.isNotEmpty(field.getValue())) {
Checkbox checkbox = new Checkbox(field.getValue());
buttons.add(checkbox);
field.setValue("");
}
});
add(
new H1("Control it!"),
buttons,
field,
button
);
}
public TextField getField() {
return field;
}
I figured out a way to avoid calling the getters
I made the Gui Application that should get data from the Vaadin a #Component too and #Autowired it into Main. This might be the wrong way, but it works.
Even though you can autowire in the Main class, if you want to use it as a bean you need to add the Spring #Component (or Vaadin's #SpringComponent) annotation, as well as #UIScope for it to return the right instance of the bean.
Is it possible to use events in Spring Boot? I need to execute one method but without waiting for return. I'm trying to use this:
public class GerarSeloEvent extends ApplicationEvent {
private TbPedido pedido;
private Integer cdCartorio;
public GerarSeloEvent(Object source, TbPedido pedido, Integer cdCartorio) {
super(source);
this.pedido = pedido;
this.cdCartorio = cdCartorio;
}
public TbPedido getPedido() {
return pedido;
}
public Integer getCdCartorio() {
return cdCartorio;
}
}
#Component
public class GerarSeloListener implements ApplicationListener<GerarSeloEvent> {
#Autowired
SeloService seloService;
#Override
public void onApplicationEvent(GerarSeloEvent event) {
seloService.gerarSelos(event.getPedido(), event.getCdCartorio());
}
}
and my call
GerarSeloEvent gerarSelos = new GerarSeloEvent(this, pedido, cdCartorio);
EnviarEmailPedidoEvent enviarEmail = new EnviarEmailPedidoEvent(this, pedido);
publisher.publishEvent(gerarSelos);
But my code waits to return anything to my front-end. I need one async event.
This should work:
#Component
public class GerarSeloListener {
private final SeloService seloService;
#Autowired
public GerarSeloListener(SeloService seloService) { ... }
#EventListener
#Async
public void handleGerarSeloEvent(GerarSeloEvent event event) {
....
}
You need to add #EnableAsync on one of your configuration (the best place is your #SpringBootApplication annotated class). But as Martin already said you don't need event if you want to process a method asynchronously: only add #Async and invoke it the usual way.
You may want to read the documentation