This is the source class:
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
@JsonSerialize(as = RequestContext.class)
public class RequestContext implements Serializable {
private static final long serialVersionUID = 1L;
private String statusCode;
private String statusType;
private String txnId;
private int channelId;
private String channel;
}
These are the target class and its parent classes:
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
@JsonSerialize(as = Transaction.class)
public class Transaction extends TransactionBase implements Serializable {
private static final long serialVersionUID = 1L;
private Actors actors = Actors.SENDER;
private PartnerMaster senderPartner;
private PartnerMaster receiverPartner;
private PartnerMaster userPartner;
private UserMaster senderUser;
private UserMaster receiverUser;
private WalletAction adjustmentType;
private BigDecimal netAmount = BigDecimal.ZERO;
private BigDecimal amount = BigDecimal.ZERO;
private BigDecimal rollbackAmount = BigDecimal.ZERO;
private Charges charges = new Charges();
private List<SystemWalletMaster> systemWallets = new ArrayList<>();
private List<SystemCdrBean> systemCdr = new ArrayList<>();
private List<Items> products;
/** generic params for dynamic values. **/
private HashMap<String, Object> genericParams = new HashMap<>();
}
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
public class TransactionBase extends TransactionFlags implements Serializable {
private static final long serialVersionUID = 1L;
private int channelId;
private String channel;
private String mvnoId;
private ServiceMaster service = new ServiceMaster();
private String featureId;
private String statusCode;
private String statusCodeReceiver;
private String statusType;
private String txnType;
private String message;
private String txnId;
private String requestId;
private long duration;
private TransactionCommon transactionCommon;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TransactionFlags implements Serializable {
private static final long serialVersionUID = 1L;
/** flags . **/
private boolean rollback;
private boolean adjustment;
private boolean adjustmentSystem;
private boolean isWhitelisted;
private boolean adjustCommission;
private boolean adjustFee;
private boolean adjustSystemCommission;
private boolean adjustSystemFee;
private boolean isLimitExists;
private boolean isLimitAllServices;
private boolean isApprovalEnabled;
}
Beans copy:
@Component
@Slf4j
public class RequestInterceptor implements HandlerInterceptor {
@Autowired
private Transaction transaction;
@Autowired
private RequestContext requestContext;
@Autowired
private UserContext userContext;
@Autowired
private CopyPropertyUtils copyPropertyUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (log.isDebugEnabled())
log.debug("{}Inside MFS Builder, building Transaction request", CONVERTER);
copyPropertyUtils.copy(requestContext, transaction);
..............
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// No implementation is done in post handle of the intercepter
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
..................
}
}
When we try to copy RequestContext to Transaction we get this error
java.lang.IllegalArgumentException: object is not an instance of declaring class
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:765) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:765) ~[spring-aop-6.1.1.jar:6.1.1]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:717) ~[spring-aop-6.1.1.jar:6.1.1]
at com.sixdee.mfs.base.beans.Transaction$$SpringCGLIB$$0.setChannel(<generated>) ~[classes/:?]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
Followed by this:
[2m2024-03-08T12:37:20.803+05:30[0;39m [31mERROR[0;39m [35m20264[0;39m [2m---[0;39m [2m${sys:LOGGED_APPLICATION_NAME}[nio-9110-exec-1][0;39m [36mc.s.d.b.e.ResponseErrorHandler [0;39m [2m:[0;39m Resource Not Found : object is not an instance of declaring class CLASS jdk.internal.reflect.NativeMethodAccessorImpl LINE -2
[2m2024-03-08T12:37:20.836+05:30[0;39m [33m WARN[0;39m [35m20264[0;39m [2m---[0;39m [2m${sys:LOGGED_APPLICATION_NAME}[nio-9110-exec-1][0;39m [36m.m.m.a.ExceptionHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.beans.FatalBeanException: Could not copy property 'channel' from source to target]
[2m2024-03-08T12:37:20.836+05:30[0;39m [32mDEBUG[0;39m [35m20264[0;39m [2m---[0;39m [2m${sys:LOGGED_APPLICATION_NAME}[nio-9110-exec-1][0;39m [36mc.s.m.b.s.e.EventManager [0;39m [2m:[0;39m Event management is in progress...
[2m2024-03-08T12:37:20.836+05:30[0;39m [31mERROR[0;39m [35m20264[0;39m [2m---[0;39m [2m${sys:LOGGED_APPLICATION_NAME}[nio-9110-exec-1][0;39m [36mo.s.w.s.HandlerExecutionChain [0;39m [2m:[0;39m HandlerInterceptor.afterCompletion threw exception
org.springframework.aop.AopInvocationException: AOP configuration seems to be invalid: tried calling method [public java.lang.String com.sixdee.mfs.base.beans.Transaction.toString()] on target [RequestContext(statusCode=DFS100, statusType=F, txnId=168421046664246, channelId=1, channel=PORTAL)]
All the properties required in the target (Transaction) are extended from its parent TransactionBase.
- If we try to move those properties to
Transactionthere will be no error. - When we tried to copy
new RequestContext()tonew Transaction()rather than the autowired beans there was no error. - The copy worked when we removed the
@Scopeannotation. - We decompiled the .class file of
Transactionand found that there were no inherited methods. - We gave all the annotations of
TransactiontoTransactionBasethe error was still occurring.
We are not able to find what is causing this issue, whether it is the issue with the source (Point-3) or the issue with the target (Point-1), all we can understand is one of the object isn't available, also the property names and types are the same. According to the comment by @M. Deinum in this post I believe the issue is with the org.springframework.beans.BeanUtils but the answer says something else.
We are using @Autowired in some scenarios and @AllArgsConstructor in some other scenarios for dependency injection, would that be causing any issues? Also, the RequestContext is a bean in parent maven project and the others are in the child maven project which depends on the parent.
Versions
Java 17
Spring Boot 3.2.0
when you use
ScopedProxyMode.TARGET_CLASSit'll use CGLIB to create a class-based proxy. So the objects of typeTransactionandRequestContextaren't the real instances, they're proxies to the concrete classes, like Andrew and M.Deinum said in the comment section. You'll need to use the concrete implementation instead of the proxy.