JsonParseException:意外字符('s'(代码115)):期望双引号开始字段名

5

我正在使用Junit和Mockito测试我的服务。我可以模拟服务并从资源类中获取响应。响应体中有一些JSON格式的数据,是对象类型。我正在尝试使用Spring Boot中Jackson库的ObjectMapper从对象中获取数据。

EmployeeResource.java

package com.ems.resource;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.ems.exception.InvalidInputDataException;
import com.ems.service.EmployeeService;
import com.ems.service.UserService;
import com.ems.util.EmailUtils;
import com.ms.base.beans.EmailObject;
import com.ms.base.entity.Employee;
import com.ms.base.entity.User;

@RestController
@RequestMapping(path = "/employee")
public class EmployeeResource 
{

    final Logger logger = LogManager.getLogger(EmployeeResource.class);
    final String EMAIL_QUEUE_NAME = "EmailQueue";
            
    @Autowired
    JmsTemplate jmsTemplate;
    
    @Autowired
    EmployeeService employeeService;
    
    @Autowired 
    UserService userService;
    
    @RequestMapping(path = "/list", method = {RequestMethod.GET, RequestMethod.POST})
    @PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_HR', 'ROLE_EMP_CRUD')")
    public ResponseEntity<Object> listEmployees() throws Exception
    {
        Map responseMap = new HashMap();
        List<Employee> employees = employeeService.getEmployees();
        
        responseMap.put("employees", employees);
        responseMap.put("status", HttpStatus.OK.value());
        responseMap.put("statusName", HttpStatus.OK.name());
        
        return new ResponseEntity(responseMap, HttpStatus.OK);
    }
}

EmployeeService.java

package com.ems.service;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ems.repository.EmployeeRepository;
import com.ms.base.entity.Employee;

@Service
public class EmployeeService 
{

    @Autowired
    EmployeeRepository employeeRepository;
    
    @Autowired
    UserService userService;
    
    
    public List<Employee> getEmployees()
    {
        return employeeRepository.findAll();
    }
}

EmployeeResourceTest.java

package com.ems.resource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.ResponseEntity;

import com.ems.service.EmployeeService;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.gson.JsonObject;
import com.ms.base.entity.Employee;

@RunWith(JUnitPlatform.class)
@ExtendWith(MockitoExtension.class)
public class EmployeeResourceTest 
{

    @InjectMocks
    private EmployeeResource employeeResource;
    
    @Mock
    private EmployeeService employeeService;
    
    
    @Test 
    public void getAllEmployees() throws Exception
    {
        
        
         // given
        Employee employee1 = new Employee();
        employee1.setId(1L);
        employee1.setName("Vineel Pellella");
        employee1.setDateOfBirth(new Date(780537600));
        employee1.setDateOfJoining(new Date());
        employee1.setDesignation("ROLE_ADMIN");
        employee1.setWorkLocation("Hyderabad");
        employee1.setContactNo(9985896040L);
        employee1.setEmail("howtodoinjava@gmail.com");

        List<Employee> employees = new ArrayList<Employee>();
        employees.addAll(Arrays.asList(employee1));
 
        when(employeeService.getEmployees()).thenReturn(employees);
 
        // when
        ResponseEntity<Object> result = employeeResource.listEmployees();
        
        // then
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        
        JsonParser parser = objectMapper.createParser(result.getBody().toString());
        
        Map respMap = objectMapper.readValue(parser, Map.class);
//        System.out.println(emp.getDateOfBirth());
        assertThat(result.getBody()).isNotNull();
        verify(employeeResource).listEmployees();
        verify(employeeService).getEmployees();
        
         
    }
    
}

Employee.java

package com.ms.base.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@NoArgsConstructor
public class Employee implements Serializable
{
    private static final long serialVersionUID = -3732596549369515261L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;    
    
    private String name;
    private String designation;
    private Date dateOfBirth;
    private Date dateOfJoining;
    private String workLocation;

    @Column(unique = true)
    private Long contactNo;
    
    @Column(unique = true)
    private String email;
    private Date dateOfLeaving;
    

}

员工存储库(employeeRepository)只是JPARepository的一个接口。
StackTrace(堆栈跟踪信息)。
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('s' (code 115)): was expecting double-quote to start field name
 at [Source: (String)"{statusName=OK, employees=[Employee(id=1, name=Vineel Pellella, designation=null, dateOfBirth=Sat Jan 10 06:18:57 IST 1970, dateOfJoining=Mon Sep 27 15:34:45 IST 2021, workLocation=Hyderabad, contactNo=9985896040, email=howtodoinjava@gmail.com, dateOfLeaving=null)], status=200}"; line: 1, column: 3]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2337)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:710)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:635)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1814)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextFieldName(ReaderBasedJsonParser.java:941)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:582)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:437)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:32)
    at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3548)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3516)
    at com.ems.resource.EmployeeResourceTest.getAllEmployees(EmployeeResourceTest.java:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.util.ArrayList.forEach(Unknown Source)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.util.ArrayList.forEach(Unknown Source)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at org.junit.platform.runner.JUnitPlatform.run(JUnitPlatform.java:139)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

result.getBody().toString()的结果:

{statusName=OK, employees=[Employee(id=1, name=Vineel Pellella, designation=ROLE_ADMIN, dateOfBirth=Sat Jan 10 06:18:57 IST 1970, dateOfJoining=Mon Sep 27 17:22:09 IST 2021, workLocation=Hyderabad, contactNo=9985896040, email=howtodoinjava@gmail.com, dateOfLeaving=null), Employee(id=2, name=Vineel Pellella2, designation=ROLE_ADMIN, ROLE_HR, dateOfBirth=Sat Jan 10 06:18:57 IST 1970, dateOfJoining=Mon Sep 27 17:22:09 IST 2021, workLocation=Bengaluru, contactNo=9985896041, email=vineel1@gmail.com, dateOfLeaving=null), Employee(id=3, name=Vineel Pellella3, designation=ROLE_ADMIN, ROLE_HR, dateOfBirth=Sat Jan 10 06:18:57 IST 1970, dateOfJoining=Mon Sep 27 17:22:09 IST 2021, workLocation=Chennai, contactNo=9985896042, email=vineel2@gmail.com, dateOfLeaving=null)], status=200}

1
展示一下 result.getBody().toString() 的内容。这似乎是相关的部分,你剩下的代码很多似乎与问题无关。 - Joachim Sauer
我将result.getBody().toString()的内容添加到了问题中。 - Vineel Pellella
这不是JSON格式。JSON应该像这样开始:{ "statusName": "OK", "employees": [ 。那看起来像是您的DTO对象的toString()方法的输出结果。 - Joachim Sauer
4个回答

5
经过长时间的研究,我尝试了以下方法,可以自动将无效的JSON转换为有效的JSON。
ObjectMapper objectMapper = new ObjectMapper();
String respData = objectMapper.writeValueAsString(result.getBody());
Map respMap = objectMapper.readValue(respData, Map.class);

com.fasterxml.jackson.core.JsonParseException: 非预期字符('u'(代码117)):期望逗号来分隔对象条目 在[来源:(StringReader); 行:1,列:62771] 在com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1851)即使我遇到了相同的错误,我尝试了上述转换也没有帮助。 - Nikhil Lingam

2

检查您是否向解析器传递了有效的 JSON 字符串。如错误日志中所述,它不是有效的 JSON:Unexpected character ('s' (code 115)): was expecting double-quote to start field name。或者,您可以添加标志 JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES 以允许处理未引用的字段名。


是的,我的JSON字符串没有引号是因为字符串内容。我已经将ObjectMapper的ALLOW_UNQUOTED_FIELD_NAMES设置为true,并且遇到了类似的错误。 com.fasterxml.jackson.core.JsonParseException: 非预期字符('='(代码61)):期望冒号分隔字段名和值。 - Vineel Pellella
由于toString方法的输出不是有效的JSON,您不能像这样解析JsonParser parser = objectMapper.createParser(result.getBody().toString()); - Darshana
请问有什么API可以在这种情况下使用吗? - Vineel Pellella
请点击此处,了解如何将POJO转换为JSON以及反向转换:[https://dev59.com/oGkw5IYBdhLWcg3w2-XH]。 - Darshana

1

我遇到了同样的问题。问题在于这不是有效的JSON。 JSON键必须是带引号的字符串。你必须引用"statusName"、"employees"等所有JSON键,直到它们都变成带引号的字符串。 希望这能解决你的问题,兄弟!


你是对的。我必须重新格式化我的 JSON。 - KnockingHeads

-1
请检查您的JSON对象是否缺少或不匹配引号!

并非所有的应用程序都能控制JSON输入。有时您需要适应上游应用程序提供带有特定属性的JSON。 - ryvantage
如果你的回答给出了如何清理输入的指示,那将会非常有帮助。 - ryvantage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接