原因:java.lang.NoSuchFieldException:修饰符

Caused by: java.lang.NoSuchFieldException: modifiers

提问人:Sreejesh 提问时间:10/31/2023 最后编辑:Sreejesh 更新时间:11/3/2023 访问量:160

问:

我正在处理现有的旧spring-boot代码,同时迁移/升级到spring-boot 2.7.16和jdk版本从8升级到21我收到此错误

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.AbstractJdbcCall;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
public class CustomJDBCCall extends SimpleJdbcCall {
private final CustomCallMetaDataContext callMetaDataContext;
private static final String CALL_META_DATA_CONTEXT = "callMetaDataContext";
private static final String MODIFIERS = "modifiers";
private static final Logger LOGGER =Logger.getLogger(CustomJDBCCall.class);

public CustomJDBCCall(JdbcTemplate jdbcTemplate) throws Exception {
    super(jdbcTemplate);
    try {
        callMetaDataContext = new CustomCallMetaDataContext();
        
        // Access private field
        Field callMetaDataContextField = 
        AbstractJdbcCall.class.getDeclaredField(CALL_META_DATA_CONTEXT);
        callMetaDataContextField.setAccessible(true);

   
        Field modifiersField = Field.class.getDeclaredField(MODIFIERS);
        modifiersField.setAccessible(true);
        modifiersField.setInt(callMetaDataContextField, 
     callMetaDataContextField.getModifiers() & ~Modifier.FINAL);


        callMetaDataContextField.set(this, this.callMetaDataContext);
      } catch (NoSuchFieldException | IllegalAccessException ex) {
        LOGGER.error("Error while using custom JDBC", ex);
        throw new RuntimeException("Exception thrown overriding 
     AbstractJdbcCall.callMetaDataContext field", ex);
     } catch (Exception ex) {
        LOGGER.error("Error while using custom JDBC", ex);
        throw ex;
     }
   }

    public List<SqlParameter> getParamerters() throws Exception {
    return this.callMetaDataContext.getCallParameters();
    }
 }

在此代码中,在行中引发异常

 Field modifiersField = Field.class.getDeclaredField(MODIFIERS);

原因:java.lang.NoSuchFieldException:修饰符 在 java.base/java.lang.Class.getDeclaredField(Class.java:2782)

之前它在 jdk 8 中工作正常。 这是不是我编写的现有代码,我认为在这里访问私有最终字段并设置值。我说得对吗? 我认为在 Jdk 版本 12 及更高版本中,无法或禁用修改最终和私有变量,是否有任何解决方法?

java spring-boot spring-jdbc java-21

评论

2赞 Mark Rotteveel 10/31/2023
自 Java 9 以来,不再允许使用这种试图修改 Java 类的技巧,例如直接使用反射。java.lang.reflect.Field
3赞 Mark Rotteveel 10/31/2023
可能不是。您可能需要重写此内容才能使用正常继承。
6赞 user85421 10/31/2023
这就是使用反射而不是公共 API 的风险 - 内部可以而且将会改变
3赞 Holger 10/31/2023
这个黑客甚至没有必要。由于该字段不是 ,因此在 .换句话说,尽管我同意其他人的说法,即你应该重新考虑这种方法。staticcallMetaDataContextField.setAccessible(true);Field callMetaDataContextField = AbstractJdbcCall.class.getDeclaredField(CALL_META_DATA_CONTEXT); callMetaDataContextField.setAccessible(true); callMetaDataContextField.set(this, this.callMetaDataContext);
3赞 Holger 10/31/2023
setAccessible(true)既可以忽略修饰符,也可以用于非静态字段的修饰符。您的后续错误是一个完全不同的问题。一般来说,也许您的框架(现在)的工作方式不兼容。privatefinalCustomCallMetaDataContext

答:

0赞 Sreejesh 11/3/2023 #1

在项目文件夹中添加了具有确切包名称的弹簧类 AbstractJdbcCall.java。 然后添加以下方法返回 callMetaDataContext

public CallMetaDataContext getCallMetaDataContext() {
    return this.callMetaDataContext;
}

现在 CustomJDBCCall 看起来像这样

 public class CustomJDBCCall extends SimpleJdbcCall {
        
 public CustomJDBCCall(JdbcTemplate jdbcTemplate) throws Exception 
  {
      super(jdbcTemplate);  
   
  }

  public List<SqlParameter> getParamerters() throws Exception {
    return this.getCallMetaDataContext().getCallParameters();
  }
 }

这解决了我的问题