I'm trying to configure Spring so that it executes advice when a specific exception subclass (MyTestException) is thrown:
public class MyTestExceptionInterceptor implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Exception exc) {
// I want this to get executed every time a MyTestException is thrown,
// regardless of the package/class/method that is throwing it.
}
}
And the XML config:
<bean name="interceptor" class="org.me.myproject.MyTestExceptionInterceptor"/>
<aop:config>
<aop:advisor advice-ref="interceptor" pointcut="execution(???)"/>
</aop:config>
I have a feeling that I should be using the target pointcut specifier (instead of execution) since - according to the Spring docs - it seems as though target allows me to specify the type of exception to match against, but I'm not sure if that's wrong, or what my pointcut attribute needs to look like.
I would greatly prefer to keep the AOP config done in XML (as opposed to Java/annotations, but I could probably translate an annotation-based solution into XML if need be.
I'd use an <aop:after-throwing> element and its throwing attribute.
Spring config
<bean name="tc" class="foo.bar.ThrowingClass"/>
<bean name="logex" class="foo.bar.LogException"/>
<aop:config>
<aop:aspect id="afterThrowingExample" ref="logex">
<aop:after-throwing method="logIt" throwing="ex"
pointcut="execution(* foo.bar.*.foo(..))"/>
</aop:aspect>
</aop:config>
The throwing attribute is the parameter name of the aspect's handler method (here it's LogException.logIt) that gets called on the exception:
Aspect
public class LogException {
public void logIt(AnException ex) {
System.out.println("*** " + ex.getMessage());
}
}
The XML and method combo defines the exception type that the aspect applies to. In this example, ThrowingClass throws AnException and AnotherException. Only AnException will have the advice applied because of the advice's method signature.
See example project on github for full source.
Check out a AfterThrowingAdvice. An example is found here (search for "After throwing advice") and you'll find it.
Related
I'm using Google Gson(gson) library form reading/writing json files and spring mvc 3 in my web application side.
So In controller, I want to create a singleton instance of Gson with pretty printing. In java the code would be,
Gson gson = new GsonBuilder().setPrettyPrinting().create();
In Controller, I created an autowired entry as below,
#Autowired
private Gson gson;
and the xml bean configuration is as below,
<bean id="gsonBuilder" class="com.google.gson.GsonBuilder">
<property name="prettyPrinting" value="true"/>
</bean>
<bean id="gson" factory-bean="gsonBuilder" factory-method="create"/>
It throws the following exception in catalina logs,
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'prettyPrinting' of bean class [com.google.gson.GsonBuilder]: Bean property 'prettyPrinting' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1024)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:900)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:58)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1358)
I knew that the setter signature of setPrettyPrinting() is different than spring expects, that's why spring is throwing the exception.
public GsonBuilder setPrettyPrinting() {
prettyPrinting = true;
return this;
}
But I'm unable to find a way to wire the builder pattern beans. I'm pretty new to spring. Can any one let me know, whether it is possible to solve this problem in xml bean approach ?
Simply use a static factory method as described in the documentation and use Java code to create Java objects: it's sooo much easier and safe:
<bean id="gson"
class="com.foo.bar.MyGsonFactory"
factory-method="create"/>
and in MyGsonFactory:
public static Gson create() {
return new GsonBuilder().setPrettyPrinting().create();
}
The setPrettyPrinting method doesn't take a parameter, so it doesn't look like a java bean property setter. That's why your approach didn't work. You can use the factory method mentioned in the other answer or use a method invoking bean in the config file like so:
<bean id="myStarter" class="org.springframework.beans.factory.config.MethodInvokingBean">
<property name="targetObject" ref="gsonBuilder"/>
<property name="targetMethod" value="setPrettyPrinting"/>
</bean>
The factory approach seems more straightforward and idiomatic to me, but I include this approach for the sake of completeness.
transaction has been initiated using following codes in Application Context file:
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*InOwnTransaction" propagation="REQUIRES_NEW"
rollback-for="com.dummy.common.exception.DummyException" />
<tx:method name="*" propagation="REQUIRED"
rollback-for="com.dummy.common.exception.DummyException" />
</tx:attributes>
</tx:advice>
In Service impl, function for updating entity
public Offering selectiveUpdateInOwnTransaction(Map<String, String> offeringData) throws DummyException
{
// search data from DB
AbstractJpaEntity priceObj = selectEntityByCriteria(Price.class, paramMap);
// now "priceObj" contain requied data;
..
priceObj.setPublishedStatus(true);
// some businesslogic which is throwing exception <-- Point 1 : This is throwing exception
priceObj.setPrice(23);
..
updateEntity(priceObj);
}
Two function calling same above mentioned function "selectiveUpdateInOwnTransaction"
public boolean updateOffering(Offering offering) // In same Service Impl
public boolean updateOfferingInOwnTransaction(....) throws DummyException // In different Service Impl
In Both these function, call to "selectiveUpdateInOwnTransaction" is as follow:
try
{
selectiveUpdateInOwnTransaction(dataMap);
}
catch (DummyException e)
{
....
}
Issue:
Point 1 is throwing exception and "priceObj" should not be updated in DB, but when "selectiveUpdateInOwnTransaction" is called from "updateOffering", it get persisted in DB.
Also only contents that are persisted in DB are contents which are updated in object before exception throw.
Call from "updateOfferingInOwnTransaction" is showing no such error.
I am not able to understand why "updateOffering" is not working as per expectation.
A workaround
As quick fix, i did following changes in "selectiveUpdateInOwnTransaction", and after that, it worked fine (entity not persisted in DB on exception throw, as expected):
Price priceObj1 = new Price();
BeanUtils.copyProperties(priceObj, priceObj1);
updateEntity(priceObj1);
But in this also, I do not understand, why this is working ?
Other configuration details
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.dummy.offering.db.service..*Service.*(..)) || execution(* com.dummy.common.db.service..*Service.*(..))" />
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
</aop:config>
If you rely on name="*InOwnTransaction" propagation="REQUIRES_NEW" to be working for the method call from updateOffering then this won't happen. You make an internal call (self-invocation) for a proxied class: the internal call to selectiveUpdateInOwnTransaction from updateOffering will be a call to a regular (non-proxied) method.
I strongly suggest to read carefully this section of the documentation.
To directly apply what you have in your code with the sample in the documentation: SimplePojo is your ServiceImpl, foo() is your updateOffering and bar() is your selectiveUpdateInOwnTransaction. Think about a proxy as an entirely new class that intercepts calls to your own methods and classes.
So, basically, when you call updateOffering from your controller you are calling updateOffering on a different class (which is not ServiceImpl) instance.
This new class applies the transactional behavior (starting a new transaction, associating transactional resources with the current thread etc) and then calls the real updateOffering from your own ServiceImpl.
updateOffering then calls selectiveUpdateInOwnTransaction, but since this call is like this.selectiveUpdateInOwnTransaction then the call would be on your ServiceImpl, not the newly created class that acts as a proxy. Because of this, Spring treats your selectiveUpdateInOwnTransaction as a regular, nothing special method.
On the other hand, if selectiveUpdateInOwnTransaction is called from anther class, that another class will call that method on the proxy, and this is why it works if you call it from a different ServiceImpl.
In that section of the documentation, there is an ugly solution to this restriction
public class SimplePojo implements Pojo {
public void foo() {
// this works, but... gah!
((Pojo) AopContext.currentProxy()).bar();
}
public void bar() {
// some logic...
}
}
but the real acceptable approach would be to redesign your classes a bit: move updateOffering to another class.
I am using Aspect for logging activities in my spring mvc based application. I am using #controller annotations to define any controller in my application. I have two different controller in two different package say
com.package1 contains controller 1 class, let's name it as AController
com.package2 contains controller 2 class, let's name it as BController
I am able to apply aspect to one particular package of controllers by using
<aop:config>
<aop:pointcut id="pointcut1"
expression="execution(* package1.*.*(..))"
id="policy1" />
<aop:aspect ref="aspect1" order="1">
<aop:before pointcut-ref="pointcut1" method="before" arg-names="joinPoint" />
<aop:after-returning returning="returnValue" arg-names="joinPoint, returnValue" pointcut-ref="pointcut1" method="after" />
</aop:aspect>
</aop:config>
<bean id="aspect1" class="com......aspectclass" />
My question is how to specify more that one different package in expression(* package1...(..))**.
Right now I am declaring one separate pointcut for each package and in aspect one separate aop:before and aop:after entry for each pointcut. But I think this should be ideal way to define multiple packages pointcut.
You can use boolean operators:
expression="execution(* package1.*.*(..)) || execution(* package2.*.*(..))"
In case you use Annotations
#Pointcut("within(com.package1..*) || within(com.package2..*)")
In spring Boot
#Before("execution(* PackageName.Controller.Service.MethodName(..))
||execution(* PackageName.Controller.Service.*.*(..))")
Example Spring-projects/AOP
#Pointcut("execution(* pakageName.anyClassNameX.*(..)) || execution(* pakageName.anyClassNameY.*(..))")
public void allMethods() {
}
#Around("allMethods()")
public Object intercept(ProceedingJoinPoint thisJoinPoint) throws Throwable {
try {
return thisJoinPoint.proceed();
} catch (Exception ex) {
}
}
I've been struggling with a configuration which requires a knowledge in AOP.
i must admit that AOP is that part i'm trying to get for a while without success.
It seems that my shiro annotations are not scanned and thus are ignored.
i've tried using shiro 1.1.0+ maven3+spring 3.0.5.RELEASE, hibernate 3.6.1.Final with ZK 5.0.6.
i got my hibernaterealm working , talking to database, i got the authentication working, i successfully(i believe) get the roles and permission loaded.
so to test the authorization side i have somewhere in my code this :
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isPermitted("businessaccount:list")) {
throw new AuthorizationException("User not authorized");
}
and it works fine.
So i know my permissions were loaded.i'll be convenient for me using annotations to i've put it in implementation class, because i didn't plan on using interface at first place with my controller classes which are extending ZK GenericForwardController.
i've seen this bug and i've decided to do a try with one interface with the #RequiresPersmissions on methods.
apparently it's still not working as in it's giving access to unauthorized subject.there is no error in my log.Maybe i'm doing something wrong here are snippet of the codes:
#Component("layouteventhandler")
public class LayoutEventHandlerImpl extends GenericForwardComposer implements LayoutEventHandler {
Logger logger = Logger.getLogger(LayoutEventHandlerImpl.class);
Menuitem logout;
//...
#Override
public void onClick$pAccounts() {
try {
execution.sendRedirect("/accounts/personal/list");
} catch (Exception ex) {
logger.info("Error redirecting to personal accounts", ex);
}
}
#Override
public void onClick$bAccounts() {
try {
execution.sendRedirect("/accounts/business/list");
} catch (Exception ex) {
logger.info("Error redirecting to business accounts", ex);
}
}
//.....
}
its interface it :
public interface LayoutEventHandler {
#RequiresPermissions(value="personalaccount:list")
public void onClick$pAccounts();
#RequiresPermissions(value="businessaccount:list")
public void onClick$bAccounts();
//.....
}
here is my shiro applicationcontext
<bean id="hibernateRealm" class="com.personal.project.admin.webapp.security.DatabaseRealm" />
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="hibernateRealm" />
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
<!-- <property name="proxyTargetClass" value="true" />-->
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations can be associated
with a Subject for security checks. -->
<bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- ... -->
is it in there something that i should do? thanks for reading and helping out
I don't know Shiro, but I'm guessing that you've put annotations on your bean classes which implement interfaces and then you're proxying them for security, transactions, and/or something else. When that happens, the object that's returned is a JDK dynamic proxy, which isn't an instance of your bean's concrete class, only of the interface it implements. Therefore any annotation scanning that depends on annotations in the concrete class won't find them.
To expand on Ryan Stewart's answer, you need to add
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
to the implementing class (not the interface) and move the Shiro annotations to it.
I encountered a similar problem when I was running two spring contexts. There is a parent root context that defined Database, Service, Security and non-SpringMVC web beans and a child web context for a Spring MVC REST api which contained the Controllers I want to proxy. The Configuration for each context was class path scanning separate packages.
In this case make sure that the DefaultAdvisorAutoProxyCreator and the AuthorizationAttributeSourceAdvisor beans that are requied are defined in the child web context (i.e. where the Rest Controllers are class path scanned) as defining them in the parent context does not work (the documentation on the DefaultAdvisorAutoProxyCreate is quite clear about this in hindsight!).
Posting this in case someone else encounters the same issue.
I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.