Unable to get the classname and method with #Before Aspect - aspectj

I have implemented AOP for logging purpose.
LoggingAspect
#Aspect
public class LoggingAspect {
private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LoggingAspect.class);
#Before("execution(public * *(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");
System.out.println("classname : " + joinPoint.getClass().getCanonicalName() + "," + joinPoint.getSignature().getName());
System.out.println("******");
}
}
and the following configuration in app-ctx.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan
base-package="com.pms" />
<aop:aspectj-autoproxy />
<bean id="loggingAspect"
class="com.pms.advice.LoggingAspect" />
</beans>
but it output for all classes I get
logBefore() is running!
classname : org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint,getConnection
******
please advice

I will never understand why so many developers call methods on JoinPoint in order to extract specific information they get for free when just logging the joinpoint instance itself. There is everything: the joinpoint type, the method signature with class name and return type. This is what you need if you really want to know what is going on in your aspects. Hiding information by just logging a part of it makes debugging so much more difficult. Plus, calling a lot of methods does not make the logging aspect faster. And then they complain AOP is "slow". ;-)
Anyway, for what it is worth, you want to use joinPoint.getSignature().getDeclaringTypeName() here. What you are logging instead are the joinpoint class and the name of the intercepted method.
Attention, joinPoint.getSignature().getDeclaringType() would give you the dynamic proxy's type which is probably not what you want.
Update: If you use ((MethodSignature) thisJoinPoint.getSignature()).get*() you have access to a couple more getters:
Method getMethod()
Class getReturnType()
Class[] getParameterTypes()
Class[] getExceptionTypes()
String[] getParameterNames()
String toString()
int getModifiers()
String getName()
String toShortString()
String toLongString()
Class getDeclaringType()
String getDeclaringTypeName()
And, interesting enough, in this case ((MethodSignature) thisJoinPoint.getSignature()).getDeclaringType() gives you the real class and not the proxy class.

I might be late to party but it might help someone.
I believe that #Aaruhi want its implemented classes to be logged. If answer is yes, then this will help:
#Before("execution(* <your_pakage_name>..*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");
System.out.println("classname : " + joinPoint.getSignature().getDeclaringTypeName() + "," + joinPoint.getSignature().getName());
System.out.println("******");
}
This will print logs for all private, public and internal methods. Please update <your_pakage_name>, this enables logging for all classes that fall under given <your_pakage_name>.
joinPoint.getSignature().getDeclaringTypeName()
- This will print your implementing class name.
NOTE - Update pointcut expression to execution(public * <your_pakage_name>..*.*(..)) to enable logging for public methods only.

Related

How to configure aop.xml when use load time weaving(AspectJ) to get parameters?

I'm tring to get something from HBase.Using AspectJ's load time weaving.I have wrote the AbstractAspect.aj and aop.xml.I also have tried use "ajc -outxml AbstractAspect.aj" to generate aop.xml,it is too simple and can not get the method's parameters.I doubt if the way(LTW) could get context.
AbstractAspect.aj:
package com.test.apectj.aj;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.GetRequest;
import com.google.protobuf.RpcController;
public abstract aspect AbstractAspect {
pointcut scan();
pointcut multi();
pointcut getdata(final RpcController controller, final GetRequest request): target(org.apache.hadoop.hbase.protobuf.generated.ClientProtos) && call (public * org.apache.hadoop.hbase.regionserver.HRegionServer.get(RpcController, GetRequest)) && args(controller, request);
pointcut scope();
before() : scan() {
System.out.println("[aop]before methon scan()");
System.out.println(thisEnclosingJoinPointStaticPart);
System.out.println(thisJoinPoint.getSourceLocation());
}
before() : multi() {
System.out.println("[aop]before methon multi()");
System.out.println("[aop]Execute multiple actions on a table: get,
mutate,and/orexecCoprocessor");
}
after() : multi(){
System.out.println("[aop]after methon multi()");
}
before(RpcController controller, GetRequest request) : getdata(controller, request)
{
System.out.println("[aop]before methon get()");
System.out.println("[aop]Get data from a table");
System.out.println(request.toString());
}
}
aop.xml:
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<concrete-aspect name="com.test.apectj.aj.ConcreteAspect"
extends="com.test.apectj.aj.AbstractAspect">
<pointcut name="scan"
expression="execution(public * org.apache.hadoop.hbase.regionserver.HRegionServer.scan(com.google.protobuf.RpcController, org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest)) AND target(org.apache.hadoop.hbase.regionserver.HRegionServer)" />
<pointcut name="multi"
expression="execution(public * org.apache.hadoop.hbase.regionserver.HRegionServer.multi(..)) AND target(org.apache.hadoop.hbase.regionserver.HRegionServer)" />
<pointcut name="getdata()"
expression="call(public * org.apache.hadoop.hbase.regionserver.HRegionServer.get(..))" />
</concrete-aspect>
</aspects>
<weaver options="-verbose -Xset:weaveJavaxPackages=true">
</weaver>
</aspectj>
when running:
no arguments[ pointcut: scan() multi() ]: success. Can print information
have arguments[ pointcut: getdata() ]: failure. Warning like this:...
[AppClassLoader#4d97507c] warning at com/test/apectj/aj/E:\EclipseWorkspace\hbase-regionserver-aop\src\com\test\apectj\aj\AbstractAspect.aj:25::0 does not match because declaring type is org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$BlockingInterface, if match desired use target(org.apache.hadoop.hbase.regionserver.HRegionServer)
[Xlint:unmatchedSuperTypeInCall]
see also: org/apache/hadoop/hbase/protobuf/generated/ClientProtos.java:28857::0
Only a simple abstract pointcut can be implemented when using this mechanism,if the mothod is not abstract.
My question is whether this way could get parameters?If possible,how to config.
Your aop.xml defines a concrete aspect providing pointcuts for two abstract base aspect pointcuts, scan() and multi(). So far, so good. But what are you trying to do with pointcut getdata(final RpcController controller, final GetRequest request)? It is already concretely defined in the base aspect, having two parameters as well as parameter binding. It seems you are trying to redefine it (same name) without any parameters and with another target. That does not make sense, and how can you expect parameter bindings if you do not define them by yourself and overwrite the existing ones (if that is possible at all, I never tried)?
Update: I forgot to mention what the warning message means:
pointcut getdata(final RpcController controller, final GetRequest request):
target(org.apache.hadoop.hbase.protobuf.generated.ClientProtos) &&
call (public * org.apache.hadoop.hbase.regionserver.HRegionServer.get(RpcController, GetRequest)) &&
args(controller, request);
If you compare the target type ClientProtos with the intercepted target method HRegionServer.get(..), you see that there is a contradiction: The target object cannot have the type ClientProtos, it must be an HRegionServer because you are intercepting a method of that class. AspectJ is friendly enough to tell you that.
Logically, this(Foo) && call(* Bar.blah(..)) is possible, because the caller type can be different from the callee type, but target(Foo) && call(* Bar.blah(..)) does not make sense because the resulting set of joinpoints will always be empty due to the fact that call(* Bar.blah(..)) always means that the target type must be Bar.

Spring3+mybatis3 generic dao(or mapper)

I have integrated spring3 + mybatis3,and it worked good.
Then I found that many SQLs will be written like this:
select * from table1 where id=#{id}
select * from table2 where id=#{id}
We don't need repeat as a programmer!
So,Can we defined a genric dao or mapper to avoid this repeat? Provide a demo is better.
Some links can help is kindly too.
It bothers me for a long time,need a hand.
I want to write my code like this:
Test.java:
just a enity.
TestMapper.java:
public interface TestMapper extends GenericMapper {
public void testMethod1(String..);
//other methods here
}
GenericMapper.java:
public interface GenericMapper<T, PK> {
public T select(PK id);
public boolean update(T t);
public boolean delete(PK id);
public boolean insert(T t);
}
defind bean in spring-xx.xml:
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="com.jackson.mapper.TestMapper" />
</bean>
Call in my service layer like this:
// Please**NOTICE**:method select is defined in GenericMapper.
TestService.java:
public TestMapper testMapper;
public Test get(Integer id) {
Test test = testMapper.select(id);
doSmth(test);
}
Just a few minutes ago,Someone said we can use a Interceptor interface. And I am trying now.
Thanks!
--jackson
One of the options is to use mybatis-generator.
http://classnotfound.net/blog/mybatisspringgenerics/
I think this tutorial has exactly what you are looking for. I am not sure what version of Java (or editor config) he is running but I had to add on the Dao methods and suppress the unchecked castings (T) and raw types warnings to get it work on eclipse mars 2 using java 8.
I know I might be late but this library from google will address your issue. I have been using it in over 10 projects.

Spring Data MongoDB: Unit tests with repositories

How is it supposed to build some tests with the repository approach in Spring Data MongoDB? I would like to set the test database for my tests since I don't want to use the production database for this purpose. It should be probably possible but I have no idea. This is my application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation=
"http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="${mongo.host}" port="${mongo.port}">
<mongo:options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="${mongo.connect-timeout}"
max-wait-time="${mongo.max-wait-time}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="${mongo.socket-timeout}"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg name="databaseName" value="${mongo.db}" />
</bean>
<context:component-scan base-package="domain.company.group.project.data.repositories"/>
<!-- MongoDB repositories -->
<mongo:repositories base-package="domain.company.group.project.data.repositories.mongodb"/>
<!-- some other stuff -->
</beans>
And let's say I have a simple repository as follows:
public interface LocationRepository extends MongoRepository<Location, String>, LocationRepositoryCustom {
}
where LocationRepositoryImpl is the class implementing all my custom methods for a certain Location (domain object) class. My test class looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/test-context.xml"})
public class LocationRepositoryTest {
#Autowired
private LocationRepository locationRepository;
/* Some tests... */
}
I have tried to embed a MongoDB instance within my running tests (as explained here) but it does not work: the connection to the test database is established but the mongo template seems not able to be overwritten as all save methods keep inserting data to the "production" database.
I am using Spring 3.2.0 and Spring Data Mongo 1.1.0.RELEASE. I am using Junit for testing.
Any suggestions?
Thank you in advance.
Jaranda,
I faced the same problem last week and coincidentally I heard about Fongo, "an in-memory java implementation of mongo."
So I decide to use it to test my custom repositories and worked perfectly to me. Below is an example of how to configure Spring to use Fongo in JUnit tests. Note that I'm not using xml configuration.
Hope that will be useful!
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class LocationRepositoryTest {
private static final String PLAYER_ID = ObjectId.get().toString();
#Autowired private LocationRepositoryCustom playerRepository;
#Autowired private MongoTemplate mongoTemplate;
/* Some tests... */
#Configuration
static class LocationRepositoryTestConfiguration {
#Bean
public Mongo mongo() {
// Configure a Fongo instance
return new Fongo("mongo-test").getMongo();
}
#Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongo(), "collection-name");
}
#Bean
public LocationRepositoryCustom playerRepository() {
// This is necessary if MongoTemplate is an argument of custom implementation constructor
return new LocationRepositoryCustomImpl(mongoTemplate());
}
}
}

get list of services implementations with OSGi declarative services

I have a very simple example of declarative services. I'm following this tutorial http://www.eclipsezone.com/eclipse/forums/t97690.html?start=0. Every thing is working as expected. However, I cannot figure out how I can make the "SampleImporter" (which is the bundle that is expected to use other bundles' services) aware of the list of "SampleExporter" (bundle providing a service). In other words, I want the "SamlpeImporter" to see the ID of the bundle(s) that it is eventually using. This information is very useful for my application.
here is the XML file for SampleExporter:
<?xml version="1.0"?>
<component name="samplerunnable">
<implementation class="org.example.ds.SampleRunnable"/>
<property name="ID" value="expoter" />
<service>
<provide interface="java.lang.Runnable"/>
</service>
while for the SampleImporter:
<?xml version="1.0"?>
<component name="commandprovider1">
<implementation class="org.example.ds.SampleCommandProvider1"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="RUNNABLE"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="0..1"
policy="dynamic"/>
</component>
In the Importer side, I have the following function:
public class SampleCommandProvider1 implements CommandProvider {
private Runnable runnable;
public synchronized void setRunnable(Runnable r) {
runnable = r;
}
public synchronized void unsetRunnable(Runnable r) {
runnable = null;
}
public synchronized void _run(CommandInterpreter ci) {
if(runnable != null) {
runnable.run();
} else {
ci.println("Error, no Runnable available");
}
}
public String getHelp() {
return "\trun - execute a Runnable service";
}
}
This works fine but then if I want to get the value of the property, using
public synchronized void setRunnable(Runnable r, Map properties)
or
public synchronized void setRunnable(Runnable r, ServiceReference reference)
the method run of the exporter is never called which means that the bind function (setRunnable is not called).Hwever, using the console command "services" I see that the exporter bundle is used by the imporeter one. Also, using ss and ls I can see that the component eporter is "satisfied".
What is wrong with my implementetion?
Thanks in advance
Cheers
Marie
The following bind signature is not supported by any version of DS:
public void setRunnable(Runnable r, ServiceReference ref)
Instead you will have to take only the ServiceReference and use either the ComponentContext or BundleContext to access the service instance object.
Alternatively if you want a more POJO-style way of accessing service properties, the following bind signature is allowed in DS 1.1 (but not in DS 1.0):
public void setRunnable(Runnable r, Map properties)
To access DS 1.1 features, you need to add the correct namespace to your XML as follows:
<component xmlns='http://www.osgi.org/xmlns/scr/v1.1.0' name='...'>
By the way, I wrote this original article a very long time ago! These days I would use bnd annotations to avoid having to write the XML document by hand.

Can XmlSerializer deserialize into a Nullable<int>?

I wanted to deserialize an XML message containing an element that can be marked nil="true" into a class with a property of type int?. The only way I could get it to work was to write my own NullableInt type which implements IXmlSerializable. Is there a better way to do it?
I wrote up the full problem and the way I solved it on my blog.
I think you need to prefix the nil="true" with a namespace in order for XmlSerializer to deserialise to null.
MSDN on xsi:nil
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="array">
<entity>
<id xsi:type="integer">1</id>
<name>Foo</name>
<parent-id xsi:type="integer" xsi:nil="true"/>
My fix is to pre-process the nodes, fixing any "nil" attributes:
public static void FixNilAttributeName(this XmlNode #this)
{
XmlAttribute nilAttribute = #this.Attributes["nil"];
if (nilAttribute == null)
{
return;
}
XmlAttribute newNil = #this.OwnerDocument.CreateAttribute("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance");
newNil.Value = nilAttribute.Value;
#this.Attributes.Remove(nilAttribute);
#this.Attributes.Append(newNil);
}
I couple this with a recursive search for child nodes, so that for any given XmlNode (or XmlDocument), I can issue a single call before deserialization. If you want to keep the original in-memory structure unmodified, work with a Clone() of the XmlNode.
The exceptionally lazy way to do it. It's fragile for a number of reasons but my XML is simple enough to warrant such a quick and dirty fix.
xmlStr = Regex.Replace(xmlStr, "nil=\"true\"", "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"");