如何解决以下问题:无法写入 JSON:无法使字段“java.lang.ThreadLocal#threadLocalHashCode”可访问?

How do I fix the following issue: Could not write JSON: Failed making field 'java.lang.ThreadLocal#threadLocalHashCode' accessible?

提问人:cloudingAround 提问时间:11/12/2023 最后编辑:cloudingAround 更新时间:11/13/2023 访问量:71

问:

我正在尝试在spring boot中为分配构建CRUD监视列表API的创建部分。我需要将我的数据存储在 json 文件而不是数据库中,以序列化和反序列化我在将新数据添加到我的监视列表时使用 gson。

问题是当我向 API 发送发布请求时,出现以下错误:

IDE 返回以下内容:

2023-11-12T12:13:11.613Z  WARN 17744 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Failed making field 'java.lang.ThreadLocal#threadLocalHashCode' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.] 

我希望当我发送发布请求时,数据会写入 gson 文件,并将新条目附加到现有监视列表的末尾

这是我写给 gson 的代码部分:



@Service
public class WriteToJson {

    private CreateWatchlist createList;
    private static final Logger log = LoggerFactory.getLogger(WriteToJson.class);

    @Autowired
    public WriteToJson(CreateWatchlist createList) {
        this.createList = createList;
    }

    Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new DateTypeAdapter()).create();

    String jsonString = gson.toJson(createList);

    public void writeToJson() throws FailureToIOJsonException {
        String jsonRepo = "JsonWatchlist.json";
        try {
           
            List<Watchlist> existingListData = gson.fromJson(jsonString, new TypeToken<List<Watchlist>>() {}.getType());

            if(existingListData == null) {
                existingListData = new ArrayList<>();
            }
            existingListData.add(createList);

            try (FileWriter writer = new FileWriter(jsonRepo, true)) {
                gson.toJson(existingListData, writer);
            } catch (IOException e) {
                log.error("Serialized watchlist failed to write to Json file.", e);
                throw new FailureToIOJsonException("IOException occurred while attempting to write new data to JSON.", e);
            }

        } catch (IOException e) {
            log.error("Failed to add createWatchlist to the new entry array", e);
            throw new FailureToIOJsonException("Exception occurred while trying to write createWatchlist to the addEntry array.", e);
        }
    }
}

下面是要序列化的数据的构造函数的输入:



@Component
public class CreateWatchlist extends Watchlist{

    private UUID uuid;
    private String stockName;
    private String symbol;
    private boolean owned;
    private String status;
    private String currency;
    private LocalDate datePurchased;
    private Integer unitsOwned;
    private double profit;
    private double pointsChange;
    private double open;
    private double close;
    private double intradayHigh;

    public CreateWatchlist() {
    super();
    }

        public CreateWatchlist(UUID uuid, String stockName, String symbol, boolean owned, String status, String currency,
            LocalDate datePurchased, Integer unitsOwned, double profit, double pointsChange, double open, double close,
            double intradayHigh) {
        super();
            
        if(uuid == null){
            this.uuid = generateUUID("default");
        }else{
            this.uuid = uuid;
        }
        this.stockName = stockName;
        this.symbol = symbol;
        this.owned = owned;
        this.status = status;
        this.currency = currency;
        this.datePurchased = datePurchased;
        this.unitsOwned = unitsOwned;
        this.profit = profit;
        this.pointsChange = pointsChange;
        this.open = open;
        this.close = close;
        this.intradayHigh = intradayHigh;
    }

    //  public CreateWatchlist() {
    // }

        public UUID generateUUID(String stockName){
        int stockNameCount = getStocknameincrement().getOrDefault(stockName, 0);
        getStocknameincrement().put(stockName, stockNameCount + 1);
        return UUID.nameUUIDFromBytes((stockName + stockNameCount).getBytes());
    }

       public UUID getUuid() {
        return uuid;
    } 

    public void setStockName(String stockName) {
        this.stockName = stockName;
    }
    public String getStockName() {
        return stockName;
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public boolean isOwned() {
        return owned;
    }

    public void setOwned(boolean owned) {
        this.owned = owned;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String currency) {
        this.currency = currency;
    }

    public LocalDate getDatePurchased() {
        return datePurchased;
    }

    public void setDatePurchased(LocalDate datePurchased) {
        this.datePurchased = datePurchased;
    }

    public Integer getUnitsOwned() {
        return unitsOwned;
    }

    public void setUnitsOwned(Integer unitsOwned) {
        this.unitsOwned = unitsOwned;
    }

    public double getProfit() {
        return profit;
    }

    public void setProfit(double profit) {
        this.profit = profit;
    }

    public double getPointsChange() {
        return pointsChange;
    }

    public void setPointsChange(double pointsChange) {
        this.pointsChange = getClose() - getOpen();
    }

    public double getOpen() {
        return open;
    }

    public void setOpen(double open) {
        this.open = open;
    }

    public double getClose() {
        return close;
    }

    public void setClose(double close) {
        this.close = close;
    }

    public double getIntradayHigh() {
        return intradayHigh;
    }

    public void setIntradayHigh(double intradayHigh) {
        this.intradayHigh = intradayHigh;
    }

        @Override
    public String toString() {
        return "WatchlistInherited [uuid=" + uuid + ", stockName=" + stockName + ", symbol=" + symbol + ", owned=" + owned + ", status=" + status + ", currency="
        + currency + ", datePurchased=" + datePurchased + ", unitsOwned=" + unitsOwned + ", profit=" + profit
        + ", pointsChange=" + pointsChange + ", open=" + open + ", close=" + close + ", intradayHigh="
        + intradayHigh + "]";
    }

}

这是我发出 POST 请求时返回的错误:

Postman 返回以下内容:

{
    "timestamp": "Nov 12, 2023, 12:13:11 PM",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Failed making field 'java.lang.ThreadLocal#threadLocalHashCode' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.\r\n\tat org.springframework.http.converter.json.AbstractJsonHttpMessageConverter.writeInternal(AbstractJsonHttpMessageConverter.java:128)\r\n\tat org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:297)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:245)\r\n\tat org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:136)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:833)\r\nCaused by: com.google.gson.JsonIOException: Failed making field 'java.lang.ThreadLocal#threadLocalHashCode' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.\r\n\tat com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:38)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:286)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)\r\n\tat com.google.gson.Gson.getAdapter(Gson.java:556)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:160)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:294)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)\r\n\tat com.google.gson.Gson.getAdapter(Gson.java:556)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:160)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:294)\r\n\tat com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)\r\n\tat com.google.gson.Gson.getAdapter(Gson.java:556)\r\n\tat com.google.gson.Gson.toJson(Gson.java:834)\r\n\tat com.google.gson.Gson.toJson(Gson.java:812)\r\n\tat com.google.gson.Gson.toJson(Gson.java:783)\r\n\tat org.springframework.http.converter.json.GsonHttpMessageConverter.writeInternal(GsonHttpMessageConverter.java:106)\r\n\tat org.springframework.http.converter.json.AbstractJsonHttpMessageConverter.writeInternal(AbstractJsonHttpMessageConverter.java:125)\r\n\t... 48 more\r\nCaused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final int java.lang.ThreadLocal.threadLocalHashCode accessible: module java.base does not \"opens java.lang\" to unnamed module @5c0e7ef1\r\n\tat java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)\r\n\tat java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)\r\n\tat java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)\r\n\tat java.base/java.lang.reflect.Field.setAccessible(Field.java:172)\r\n\tat com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:35)\r\n\t... 64 more\r\n",
    "message": "Could not write JSON: Failed making field 'java.lang.ThreadLocal#threadLocalHashCode' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.",
    "path": "/watchlist/addEntry"
}

我无法找到解决此问题的方法,如果能提供任何帮助,我将不胜感激。

这是下面监视列表中的代码。当我在 postman 中发送 POST 请求时,我收到上面显示的两条消息,我将返回并突出显示它们。

    public class Watchlist {

//     @JsonProperty
    private static final Map<String, Integer> stockNameIncrement = new HashMap<>();

    public static Map<String, Integer> getStockNameIncrement() {
        return stockNameIncrement;
    }
}
java spring-boot gson crud 线程本地

评论

0赞 Marcono1234 11/13/2023
请同时附上您的班级代码;最有可能的是,它有一个 类型的字段。此外,还请包括异常的堆栈跟踪,或至少包含其中的一部分。我也不确定您写入 a 的逻辑是否真的像预期的那样工作,因为这只会附加另一个顶级 JSON 值,而不是将新元素添加到该文件中的现有 JSON 数组中。WatchlistThreadLocalFileWriter(..., append=true)
0赞 Marcono1234 11/15/2023
根据 Postman 响应中的堆栈跟踪,看起来这实际上可能与您的类无关(它不会出现在堆栈跟踪中的任何位置)。您能否包含定义 REST API 的 Spring 控制器类的代码?看起来这可能隐式地使用 Gson 来序列化具有值的对象。WriteToJsonThreadLocal

答: 暂无答案