AspectJ #DeclareParents defaultImpl code is not used when using it as dependency - java

I am working with AspectJ at the moment.
I seperated AspectJ code in a dependency.
Within that dependency everything works as intended.
But as soon as I import it in another project only some functionality does not work anymore.
When using the defaultImpl of #DeclareParents, the interface is shown within the compiled code but not the default Implementation.
Here is my code to show what I mean (every code snippet is its own File):
AspectJ code:
public interface IAspect
{
String hello();
}
public class IAspectDefaultImpl implements IAspect
{
#Override
public String hello()
{
return "hello";
}
}
#Aspect
public class AspectJ
{
#DeclareParents(value = "#SomeAnnotation*", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
}
Target Class in a different project:
#SomeAnnotation
public class MyClass
{
private final int myValue;
public MyClass(final int wert)
{
this.myValue = wert;
}
public int getMyValue()
{
return myValue;
}
}
Maven throws me:
The type MyClass must implement the inherited abstract method IAspect.hello()
Which implies that it works partially.
When looking at the decompiled .class files the targeted Class does in fact implement IAspect.
The method defined in IAspectDefaultImpl is still missing tho.
My pom is set up like in this example.
I am not sure where I should start to look for errors.
Any help is apreciated.

Thanks for the MCVE. But hey, you don't use Git in order to commit 7z or ZIP archives, you ought to commit source code. I forked your project and fixed that, restructured and simplified your POMs and also fixed the main problem.
See my pull request and the commits in it for further details.
Concerning your problem, I can confirm that it occurs if you use #DeclareParents the way you do in an aspect library.
Actually, according to AspectJ maintainer Andy Clement there are certain problems with #DeclareParents when using it to provide parent interfaces + implementations in annotation style. The native AspectJ syntax via declare parents is not affected by that, but for annotation-style syntax Andy provided an alternative called #DeclareMixin, see the AspectJ manual. There he mentions that he is even considering to deprecate the defaultImpl argument of #DeclareParents in favour of #DeclareMixin.
So my bugfix (or workaround) for your problems is to actually replace
#DeclareParents(value = "#de.example.aspect.SomeAnnotation *", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
by
#DeclareMixin("#de.example.aspect.SomeAnnotation *")
public static IAspect createIAspectImplementation() {
return new IAspectDefaultImpl();
}
This works with aspect libraries.
I will discuss with Andy about whether it makes sense to file a bug ticket for your problem or if he won't fix it anyway because there is a viable and recommended alternative.

Related

How to create method that could be used only for tests

Are the any ways to create method/contractor that could be used only in Junit ( test purpose only ) ?
Maybe there is an annotation?
For methods that are only used for testing... why not make them part of the actual test-code? At least in build-systems such as Maven, test code is not included in packaged jars, and is only distributed as part of the sources. In that sense, it cannot be called from normal classes, since it is simply not included in the final .jar (or .war).
I very frequently write such methods to make my test-code more maintainable.
To clarify:
src/
main/
java/
my/package/
MyClass.java <-- leave necessary protected accessors here
test/
java/
my/package/
MyClassTest.java <-- implement test-code here
And in MyClassTest...
public class MyClassTest {
...
private static Foo doSomethingCoolButTesty(MyClass instance) {
// access protected or package-private MyClass code here
}
}
MyClassTest.doSomethingCoolButTesty will be kept separate from the main code, and will obviously only be available to test code. Yes, it is somewhat uglier than including it as a method of the main code, but I find a fair price to pay.
For what purpose do you need this method?
(J)UnitTests should verify the behavior of the class by using its public interface. No "special" method in the tested code should be used in unit tests.
But Unittests should replace the dependencies of the tested code with test doubles (aka fakes and mocks). The preferred way to provide those test doubles is dependency injection (DI).
Sometimes its to much effort to introduce DI to your code. In that case it is acceptable to introduce low visibility getter methods as a seam where the dependency can be replaced by the mock.
class CodeUnderTest{
private final SomeOtherClass dependency = new SomeOtherClass();
SomeOtherClass getDependency(){ // package private getter
return dependency;
}
public void doSomething(){
dependency.expectedMethodCalled();
}
}
class TestInSamePackage{
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Mock
private SomeOtherClass testDouble;
#Spy
private CodeUnderTest cut;
#Before
public void setup(){
doReturn(testDouble).when(cut).getDependency();
}
#Test
public void shouldDoSomething() {
// configure testDouble
cut.doSomething();
verify(testDouble).expectedMethodCalled();
}
}
There is nothing that would prevent to call methods "outside" of a junit test case.
My pragmatic answer: make the method package protected and add a simple comment like "unit test only" as javadoc. And educate your team to honor such statements.
And ideally: design your production code in a way that does not require such "tricks" in order to make it testable!
Given the comments on the question: it might be technically possible to somehow acquire stack trace information; to then search for the presence of #Test annotations on the corresponding methods. But that seems to be absolute overkill - and it would mean to add even more "test only" code into the production code.
And it would also be the wrong approach - as it tries to solve a "social" problem using technical means: if you don't want that people are calling a certain method - then make sure they understand that.

Gradle release build - preserving method parameter names

We are creating an Android library with an inner interface class. The problem we are facing is that the method parameter names are not preserved for interface class in the release build aar file. Although .aar file works fine, this creates problem in editor when using autocompletion, Implement methods etc. Please note that proguard is disabled.
public class Test {
public interface TestInterface {
void testCallback(int ordernumber, int vendorid);
}
public boolean init(Context context);
}
In the debug build, class is preserved fine. However, in the release build, parameter names of interface methods are not preserved. Interestingly it preserves parameter names of class methods. This I verified using decompiler.
public class Test {
public interface TestInterface {
void testCallback(int paramInt1, int paramInt2);
}
public boolean init(Context context);
}
I also tried setting debuggable flag in buildconfig without any help.
Will appreciate any help.
The official oracle docs state that interfaces do not preserve parameter names, so the only solution is including the docs with the library: Preserving parameter/argument names in compiled java classes

Java calling unknown code or method from, not yet, existing dependency

i have two independent projects Basic and Extension with following setup
Project A:
class Handler {
public void handle(){
...
}
}
Project B
import Handler; //from Proejct A
class SomeClass{
someMethod() {
handle(); //dependency to Project As class with handle method
}
}
So the problem is the dependecy to the handle method which exists at Project A but not at compile time on Project B.
The final step is to have build Project Extension as a jar and import it inside Project Basic.
Ofc the compiler will give me error when i build Project B since the handle is not known at compile time.
For this issue i need a solution:
Either: Tell java that the missing code (import class with handle method) will be there at running time.
Or maybe Dependency Injection due to a factory pattern.
I am known to the factory pattern, but i don't understand how it could help me in this situation.
Or another solution.
Can you help me?
Neither of these are valid Java - won't compile. The proper keyword is "class", not "Class".
You have to provide it at compile time once you get it right - you have no choice. No way around it.
Maybe you should look at the Java JDK and follow the example in the java.sql package: Interfaces. Connection, ResultSet, Statement, etc. are all interfaces so vendors can provide their own implementations. Users only deal with interfaces.
Your GenericHandler should be an interface that you provide to clients. They add their implementations and add their JAR file containing the custom implementation at runtime.
Basic interface that all extensions implement:
public interface GenericHandler {
void genericHandle();
}
Extension code:
import GenericHandler;
public class Extension implements GenericHandler {
public void genericHandle() {
// Do something useful here
}
}
The factory pattern works only if you provide a finite, closed set of implementations:
public class GenericHandlerFactory {
private final GenericHandlerFactory instance = new GenericHandlerFactory();
private GenericHandlerFactory() {}
public GenericHandler getInstance() { return this.instance; }
public GenericHandler createHandler(Class genericHandlerClass) {
GenericHandler result = null;
// Code to create the GenericHandler you want.
return result;
}
}
If users can extend your interface without your knowledge then a factory can't work; you have to stick to the JDBC example.

Is there a Java wrapper annotation?

Trying to find a way to wraps an object, which is auto generated based on some model with lots of getters and setters. For example:
class ObjectToWrap {
public int getIntA();
public int getIntB();
... // Tons of other getters
}
I have to create a wrapper that wraps this object and use some annotation that generates methods from ObjectToWrap for me. Code looks like the following:
class Wrapper {
private ObjectToWrap obj;
public int getIntA() {
return obj.getIntA();
}
public int getIntB() {
return obj.getIntB();
}
... // Tons of other getters
}
Is there an annotation to do this? I just don't want to make the code look lengthy.
Take a look at Project Lombok which has a #Delegate annotation which does exactly what you want.
#Delegate documentation
I think you would be able to do this:
import lombok.Delegate;
class Wrapper {
//the types field in the annotation says
//to only auto generate deleagate methods
//for only the public methods in the ObjectToWrap class
//and not any parent classes if ObjectToWrap extended something
#Delegate(types = ObjectToWrap.class)
private ObjectToWrap obj;
}
If you are using the maven build infrastructure with dependency management, you could have a dependent sub-project that collects the generated sources as-is (not as code). Another sub-project could then generate real sources out of them (source code transformation) as zip, which then could be imported by maven in the main project as pre-compile target.
On that basis you could use dynamic proxy classes, or even immediate generated classes.
The only other alternative would be to use the java scripting API, and do the business in JavaScript or so. Loosing the type safeness of java and lowering the software quality.
Unfortunately the alternative of hybrid usage of another JVM language I cannot consider productive. The very nice and powerful Scala still is too wild/complex/ticklish.

Class '...' must be declared as 'abstract'. Checkstyle

I have this warning on most of my classes and not sure why is that. This happens on both public normal classes and final classes which have private constructors, some no constructor at all. I tried changing my private class methods to protected, doesn't help. Any suggestions on how to turn this off?
Here's a class example
public final class PlanBenefitManagerAssembler {
private static final Logger LOGGER = Logger.getLogger(PlanBenefitManagerAssembler.class);
/**
* No Instance of the this class is allowed.
*/
private PlanBenefitManagerAssembler() {
}
public static List<BenefitDecisionDetailsBean> assembleBenefitDecisionDetailsBean(
List<BenefitDetails> benefitDecisionDetailsList, int relationalSequenceNumber) {
LOGGER.debug("Enter assembleBenefitDecisionDetailsBean");
List<BenefitDecisionDetailsBean> benefitDecisionDetailsBeanList = new ArrayList<BenefitDecisionDetailsBean>();
for (BenefitDetails benefitDecisionDetails : benefitDecisionDetailsList) {
BenefitDecisionDetailsBean benefitDecisionDetailsBean = new BenefitDecisionDetailsBean();
benefitDecisionDetailsBean.setBenefitTypeCode(benefitDecisionDetails.getBenefitTypeCode());
benefitDecisionDetailsBean.setRelationSequenceNumber(relationalSequenceNumber);
benefitDecisionDetailsBean.setBenefitStatusDescription(
benefitDecisionDetails.getBenefitStatusDescription());
benefitDecisionDetailsBean.setBenefitStatusCode(benefitDecisionDetails.getBenefitStatusCode());
benefitDecisionDetailsBean.setBenefitUnderwritingStatusCode(
benefitDecisionDetails.getBenefitUnderwritingStatusCode());
benefitDecisionDetailsBean.setBenefitUnderwritingStatusDescription(
benefitDecisionDetails.getBenefitUnderwritingStatusDescription());
benefitDecisionDetailsBean.setBenefitChangeReasonCode(
String.valueOf(benefitDecisionDetails.getBenefitChangeReasonCode()));
benefitDecisionDetailsBean.setBenefitChangeReasonDescription(
benefitDecisionDetails.getBenefitChangeReasonDescription());
benefitDecisionDetailsBean.setComponentNumber(benefitDecisionDetails.getBenefitNumber());
benefitDecisionDetailsBean.setBenefitVisible(benefitDecisionDetails.isExplicitBenefitDecisionRequired());
benefitDecisionDetailsBean.setModelChanged(false);
// * Set BenefitLoading and BenefitExclusion
List<ExclusionDetailsBean> exclusionDetailsBeanList =
PlanBenefitManagerAssembler.assembleExclusionDetailsList(benefitDecisionDetails
.getBenefitExclusionsDetailsList().getBenefitExclusionsDetailsList());
List<LoadingDetailsBean> loadingDetailsBeanList =
PlanBenefitManagerAssembler.assembleLoadingDetailsList(benefitDecisionDetails
.getBenefitLoadingsDetailsList().getBenefitLoadingsDetailsList());
benefitDecisionDetailsBean.setExclusionDetailsBeanList(exclusionDetailsBeanList);
benefitDecisionDetailsBean.setLoadingDetailsBeanList(loadingDetailsBeanList);
benefitDecisionDetailsBeanList.add(benefitDecisionDetailsBean);
}
LOGGER.debug("Exit assembleBenefitDecisionDetailsBean");
return benefitDecisionDetailsBeanList;
}
}
When Checkstyle produces a warning the warning text should include a short rule name which will allow you to look up the exact rule that is being triggered. "DesignForExtension", for example.
Given the rule name, you can look up more detail on what it means in the Checkstyle documentation: http://checkstyle.sourceforge.net/availablechecks.html
Post the full details of the rule being triggered and someone might be able to help.
You can always turn the warnings off, but they generally are here for a reason :)
Do you intend to make them abstract classes ? If so, declare them that way.
Will you need to instantiate them at some point ? If so, add a public constructor.
I'm pretty sure this will solve your problem.
On sourceforge it says that the AbstractClassName rule uses the following regex:
^Abstract.*$|^.*Factory$
This causes classes with a name starting with 'Abstract' or ending with 'Factory' to be flagged. I get the 'Abstract..' part of that, but why should all '..Factory' classes be abstract? Sometimes I create factories which use dependencies to do their work so I need an instance to inject into.
This however does not explain your case. I tried your example class and did not get any Checkstyle warning (I am using the Eclipse Checkstyle Plug-in version 5.3.0.201012121300).
Are you sure you are getting the AbstractClassName warning for this class? Which version of Checkstyle are you using?

Categories