after decompiling my interface i found out that proguard duplicated my implemented method in the upper level interface that is somehow a class on its own right.
here's how my interface looks like after obfuscation (note that proguard even added the annotation from the implementation)
package com.company.project.f.a.a;
import java.util.List;
import org.apache.log4j.Logger;
#Component(value="ServiceImpl")
public class a
{
public b a(int i)
{
if((i = b.a(i)) != null)
{
if(i.size() == 0)
{
a_.fatal("It is expected at least one record.");
return null;
} else
{
return (b)i.get(0);
}
} else
{
return null;
}
}
public a()
{
a_ = Logger.getLogger(getClass());
}
public com.company.project.b.a.a a()
{
return b;
}
public void a(com.company.project.b.a.a a1)
{
b = a1;
}
private com.company.project.b.a.a b;
Logger a_;
}
same issue happened with the class below (proguard transforming the interface into a class with the same component name)
#Component("testDao")
public class TestDaoImpl implements TestDao {
#Override
public void testing() {
// TODO Auto-generated method stub
}
solved it :
according to mr eric lafortune , the optimizer is merging interface and class .
so i used
-dontoptimize
Related
Is it customary to write a singleton containing the class from which it creates an object and in addition this class contains a private constructor so that it is not possible to create another object from this class by the 'new' keyword?
package com.isi.core;
import com.isi.handlers.MouseMotionHandler;
import com.isi.states.MainMenuState;
import com.isi.states.PlayState;
import com.isi.uicomponents.Button;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Singleton {
private static MouseHandler instance = null;
public static MouseHandler getInstance(Game game) {
if (instance == null)
instance = new MouseHandler(game);
return instance;
}
public static class MouseHandler extends MouseAdapter {
private Game game;
private MouseHandler(Game game) {
this.game = game;
}
public void mousePressed(MouseEvent e) {
MouseMotionHandler mouseMotionHandler = game.getMouseMotionHandler();
if (mouseMotionHandler.getOnComponent() != null && e.getButton() == 1 && mouseMotionHandler.getOnComponent() instanceof Button) {
Button button = (Button) mouseMotionHandler.getOnComponent();
if (game.getState() instanceof MainMenuState) {
if (button.getText().getString().equals("Play")) {
game.getGameStateManager().push(new PlayState(game));
} else if (button.getText().getString().equals("Exit")) {
System.exit(0);
}
}
}
}
public void mouseReleased(MouseEvent e) {
}
}
}
I created a singleton class that returns a single MouseHandler created from a private MouseHandler constructor.
I upgraded my spring stream from 1.3.0 to 2.1.2 and the default serializer was changed from Kyro (deprecated) into Jackson.
I have a kafka topic that more than one type of messages can be sent to. With Kyro I used to deserialize it into Object.class and then cast it to the relevant type of class.
With jackson I can't achieve this functionality, because I have to specify the type of class I want to deserialize to in advance, otherwise, it's been deserialized into a string.
I tried to find an example but couldn't find anything. Any ideas how can I achieve the same functionality? I want to make it as efficient as possible.
You can add hints to the Jackson encoding so it is decoded to the right concrete type:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
#SpringBootApplication
#EnableBinding(Processor.class)
public class So56753956Application {
public static void main(String[] args) {
SpringApplication.run(So56753956Application.class, args);
}
#StreamListener(Processor.INPUT)
public void listen(Foo foo) {
System.out.println(foo);
}
#Bean
public ApplicationRunner runner(MessageChannel output) {
return args -> {
output.send(new GenericMessage<>(new Bar("fiz")));
output.send(new GenericMessage<>(new Baz("buz")));
};
}
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
public static abstract class Foo {
private String bar;
public Foo() {
super();
}
public Foo(String bar) {
this.bar = bar;
}
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return getClass().getName() + " [bar=" + this.bar + "]";
}
}
public static class Bar extends Foo {
public Bar() {
super();
}
public Bar(String bar) {
super(bar);
}
}
public static class Baz extends Foo {
public Baz() {
super();
}
public Baz(String bar) {
super(bar);
}
}
}
and
com.example.So56753956Application$Bar [bar=fiz]
com.example.So56753956Application$Baz [bar=buz]
See here.
You can still use Kryo if you want. You can just add it manually using #StreamMessageConverter- https://cloud.spring.io/spring-cloud-stream/spring-cloud-stream.html#spring-cloud-stream-overview-user-defined-message-converters.
With regard to "With jackson I can't achieve this functionality, because I have to specify the type of class. . ." - that is not accurate since the type of the class gets picked up from the signature of the handler method and it is transparent to you as a user.
I have the following implementation:
public interface BusinessResource {
#RequiresAuthorization
public ResponseEnvelope getResource(ParamObj param);
}
and
#Component
public class BusinessResourceImpl implements BusinessResource {
#Autowired
public Response getResource(ParamObj param) {
return Response.ok().build();
}
}
and
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class AuthorizerAspect {
protected static final Logger LOGGER =
LoggerFactory.getLogger(AuthorizerAspect.class);
#Autowired
public AuthorizerAspect() {
LOGGER.info("Break point works here..." +
"so spring is creating the aspect as a component...");
}
#Around(value="#annotation(annotation)")
public Object intercept(ProceedingJoinPoint jp,
RequiresAuthorization annotation) throws Throwable {
LOGGER.info("BEGIN");
jp.proceed();
LOGGER.info("END");
}
}
The maven dependencies are properly configured with the spring-boot-starter-aop dependency. So what happens is that AuthorizerAspect won't intercept around the getResource method if the #RequiresAuthorization is used on the declared method of the BusinessResource interface, but if I change the implementation to annotate the same method now in the BusinessResourceImpl class, the aspect will take place.
NOTE: With the annotation in the interface level, the proxy isn't even created, whereas the annotation being placed in the implementation level will create a proxy for the resource.
Question is: Is there a way to advice objects which the annotation is present just on the interface?
May this alternative be useful for those who like me found no direct approach to sort that limitation on Spring AOP through proxies:
public interface BusinessResource {
#RequiresAuthorization
public ResponseEnvelope getResource(ParamObj param);
}
And
#Component
public class BusinessResourceImpl implements BusinessResource {
#Autowired
public Response getResource(ParamObj param) {
return Response.ok().build();
}
}
And
import import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
#Configuration
public class AuthorizerAspect {
protected static final Logger LOGGER =
LoggerFactory.getLogger(AuthorizerAspect.class);
#Autowired
public AuthorizerAspect() {
LOGGER.info("Break point works here..." +
"so spring is creating the aspect as a component...");
}
public Object invoke(MethodInvocation invocation) throws Throwable {
LOGGER.info("BEGIN");
invocation.proceed();
LOGGER.info("END");
}
#Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
#Bean("requiresAuthorizationPointcut")
public AbstractPointcutAdvisor createPointcut() {
return new AbstractPointcutAdvisor() {
private static final long serialVersionUID = 4733447191475535406L;
#Override
public Advice getAdvice() {
return AuthorizerAspect.this;
}
#Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
#Override
public boolean matches(Method method, Class<?> targetClass) {
if (method.isAnnotationPresent(RequiresAuthorization.class)) {
return true;
}
if (method.getDeclaringClass().isInterface()) {
String methodName = method.getName();
try {
Method targetMethod = targetClass.getMethod(methodName, method.getParameterTypes());
return targetMethod != null && targetMethod.isAnnotationPresent(RequiresAuthorization.class);
} catch (NoSuchMethodException |
SecurityException e) {
LOGGER.debug("FAILURE LOG HERE",
e.getMessage());
return false;
}
}
return method.isAnnotationPresent(RequiresAuthorization.class);
}
};
}
};
}
}
So as you'll notice, we're sorting it by using method interceptors.
Trying to apply a MockUp on a Java 8 default interface method, and JMockit tells me that method cannot be found. This has been tried with JMockit 1.15, 1.19, and 1.25. Here's a very simple use case:
#RunWith(JMockit.class)
public class TestTest {
public interface MyInterface {
default void foo(int f) {
bar(String.valueOf(f));
}
void bar(String s);
}
public class MyClass implements MyInterface {
public void bar(String s) {
System.out.println(s);
}
}
#Test
public void testtest() throws Exception {
new MockUp<MyClass>() {
#Mock
void foo(int i) {
System.out.println("MOCKMOCK " + (i*2));
}
#Mock
void bar(String s) {
System.out.println("MOCK " + s);
}
};
MyClass baz = new MyClass();
baz.foo(5);
baz.bar("Hello world");
}
}
This gets me the error
java.lang.IllegalArgumentException: Matching real methods not found for the following mocks:
com.example.dcsohl.TestTest$1#foo(int)
at com.example.dcsohl.TestTest$1.<init>(TestTest.java:29)
at com.example.dcsohl.TestTest.testtest(TestTest.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
How can we #Mock this method?
Slightly modifying your use case to return strings instead of printing to standard out the following solution will work.
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import mockit.Expectations;
public class TestTest {
public interface MyInterface {
default String foo(int f) {
return bar(String.valueOf(f));
}
String bar(String s);
}
public class MyClass implements MyInterface {
public String bar(String s) {
return s;
}
}
#Test
public void testtest() throws Exception {
MyClass baz = new MyClass();
new Expectations(MyClass.class) {{
baz.foo(anyInt); result = "FOOMOCK";
baz.bar(anyString); result = "BARMOCK";
}};
assertEquals(baz.foo(5), "FOOMOCK");
assertEquals(baz.bar("Hello world"), "BARMOCK");
}
}
There are many useful examples of how to mock out interfaces with method bodies (ie default or static methods) outlined in the examples section on the jmockit github repository.
Use #Mocked instead of a MockUp, it supports default methods.
My goal is to be able to override what I get back from CustomClass.class.getName() and CustomClass.getClass().getName()
It should return a custom value, which I think is best to define in an attribute like
#NameOverride("Custom.fully.qualified.class.name")
public class CustomClass {}
Is there any way to do that?
Fred's answer is okay, but his aspect could be somewhat more elegant with less code and especially fewer reflection calls. Sorry, I prefer AspectJ native code style, but #AspectJ annotation style would not be much longer:
String around(Class clazz) : call(public String Class.getName()) && target(clazz) {
NameOverride nameOverride = (NameOverride) clazz.getAnnotation(NameOverride.class);
return nameOverride == null ? proceed(clazz) : nameOverride.value();
}
Here is the full source code. I added a class without annotation to show the different behaviour and also a restriction to class definitions - #Target(ElementType.TYPE) - to the annotation class. I am also showing package names and imports:
package test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface NameOverride {
String value();
}
package test;
public class NormalClass {}
package test;
#NameOverride("Custom.fully.qualified.class.name")
public class CustomClass {}
package test;
public class Main {
public static void main(String[] args) {
System.out.println(NormalClass.class.getName());
System.out.println(CustomClass.class.getName());
System.out.println(new NormalClass().getClass().getName());
System.out.println(new CustomClass().getClass().getName());
}
}
package aspectj;
import test.NameOverride;
public aspect GetNameOverrider {
#SuppressWarnings({ "unchecked", "rawtypes" })
String around(Class clazz) : call(public String Class.getName()) && target(clazz) {
NameOverride nameOverride = (NameOverride) clazz.getAnnotation(NameOverride.class);
return nameOverride == null ? proceed(clazz) : nameOverride.value();
}
}
The output:
test.NormalClass
Custom.fully.qualified.class.name
test.NormalClass
Custom.fully.qualified.class.name
This is for sure not the best/fastest solution but maybe a POC...
First of all the file structure:
./src/aspectj:
GetNameOverrider.aj
./src/test:
CustomClass.java Main.java NameOverride.java
NameOverride.java:
#Retention(RetentionPolicy.RUNTIME)
public #interface NameOverride {
String value();
}
GetNameOverrider.aj:
#Aspect
public class GetNameOverrider {
#Around("call(String getName()) && !within(aspectj..*)")
public String advice(ProceedingJoinPoint pjp) throws Throwable {
String ret = (String) pjp.proceed();
String className = "" + pjp.getTarget();
className = className.replace("class ", "");
try {
test.NameOverride anno = Class.forName(className).getAnnotation(
test.NameOverride.class);
if (anno != null) {
return anno.value();
}
} catch (ClassNotFoundException e) {
return ret;
}
return ret;
}
}
gives me for Main.java:
public class Main {
public static void main(String[] args) {
System.out.println(CustomClass.class.getName());
System.out.println(new CustomClass().getClass().getName());
}
}
the output:
Custom.fully.qualified.class.name
Custom.fully.qualified.class.name