【问题标题】:Java Jackson object mapper fails on correct variable nameJava Jackson 对象映射器在正确的变量名上失败
【发布时间】:2019-02-04 19:36:26
【问题描述】:

注意:我知道变量命名不正确。我正在清理另一个将这些列为成员变量的开发人员的旧代码。它们将被正确命名,是的,我知道我需要注释,但我在这里寻找的是关于为什么变量是 EmployeeId 的解释,它正在寻找 EmployeeID,但找到一个不存在的变量 mEmployeeId。顺便说一句,这发生在服务器上,而不仅仅是在 IDE 中。

由于一些未知的原因 - 在修改变量名、保存、重新启动、使缓存失效等所有内容之后 - jackson 无法映射到 propper 变量名。为此,我正在使用 IntelliJ 和 Java。

错误:

Exception in badge service getting by badgeId: Unrecognized field 
"EmployeeId" (class com.companyName.attendance.entity.DTOs.badgeservice.BadgeDTO), not marked as ignorable (6 known properties: "mBadgeId", "mEmployeeId", "mLanId", "mFirstName", "mEmail", "mLastName"]) 
at [Source: (String)"{"backoff":null,"error_id":null,"error_message":null,"error_name":null,"has_more":false,"items":[{"EmployeeId":"888888","LanId":"NTest","FirstName":"Name","MiddleName":null,"LastName":"Test","Email":null,"Location":null,"Title":null,"Phone":null,"DepartmentId":null,"DepartmentName":null,"DepartmentNumber":null,"Groups":null,"Found":false,"BadgeId":"222222","JobTitle":null,"Picture":null,"OrgUrl":null,"Manager":null,"Coworkers":null,"DirectReports":null}],"page":null,"page_size":null,"quo"[truncated 61 chars]; line: 1, column: 113] (through reference chain: com.companyName.attendance.entity.DTOs.badgeservice.BadgeServiceResponseDTO["items"]->java.util.ArrayList[0]->com.companyName.attendance.entity.DTOs.badgeservice.BadgeDTO["EmployeeId"])

如您所见,它没有在 DTO 中找到 EmployeeId,并说预期的字段是 mEmployeeID。但是,这是我的 DTO 变量声明:

public class BadgeDTO {
//TODO: Convert member variables to proper practice names
String BadgeId;
String EmployeeId;
String FirstName;
String LanId;
String LastName;
String Email;

public BadgeDTO(String BadgeId, String EmployeeId, String FirstName, 
String LanId, String LastName, String Email) {
    super();
    this.BadgeId = BadgeId;
    this.EmployeeId = EmployeeId;
    this.FirstName = FirstName;
    this.LanId = LanId;
    this.LastName = LastName;
    this.Email = Email;
}
public BadgeDTO() {
    super();
}
public String getmBadgeId() {
    return BadgeId;
}
public void setmBadgeId(String BadgeId) {
    this.BadgeId = BadgeId;
}
public String getmEmployeeId() {
    return EmployeeId;
}
public void setmEmployeeId(String EmployeeId) {
    this.EmployeeId = EmployeeId;
}
public String getmFirstname() {
    return FirstName;
}
public void setmFirstName(String FirstName) {
    this.FirstName = FirstName;
}
public String getmLanId() {
    return LanId;
}
public void setmLanId(String LanId) {
    this.LanId = LanId;
}
public String getmLastName() {
    return LastName;
}
public void setmLastName(String LastName) {
    this.LastName = LastName;
}
public String getmEmail() {
    return Email;
}
public void setmEmail(String Email) {
    this.Email = Email;
}
@Override
public String toString() {
    return "BadgeDTO [BadgeId=" + BadgeId + ", EmployeeId=" + EmployeeId + 
", Firstname=" + FirstName
            + ", LanId=" + LanId + ", LastName=" + LastName + ", Email=" + 
Email + "]";
}
}

现在最疯狂的是,执行以下操作:

@JsonProperty("BadgeId")
String BadgeId;
@JsonProperty("EmployeeId")
String EmployeeId;
@JsonProperty("FirstName")
String FirstName;

JSON:

{
"backoff": null,
"error_id": null,
"error_message": null,
"error_name": null,
"has_more": false,
"items": [
    {
        "EmployeeId": "888888",
        "LanId": "TName",
        "FirstName": "Test",
        "MiddleName": null,
        "LastName": "Name",
        "Email": null,
        "Location": null,
        "Title": null,
        "Phone": null,
        "DepartmentId": null,
        "DepartmentName": null,
        "DepartmentNumber": null,
        "Groups": null,
        "Found": false,
        "BadgeId": "222222",
        "JobTitle": null,
        "Picture": null,
        "OrgUrl": null,
        "Manager": null,
        "Coworkers": null,
        "DirectReports": null
    }
],
"page": null,
"page_size": null,
"quota_max": null,
"quota_remaining": null,
"total": null,
"type": null
}

所以,我已经使用上面的 JsonProperty 注释解决了这个问题,但是为什么它仍然在寻找我的整个代码中不存在的 mEmployeeId 呢?我认为 invalidate/restart 会解决这个问题,但它没有

【问题讨论】:

  • Java 中的好习惯是以小写开头的实例/变量名:String String BadgeId should be String badgeId;...
  • 是的,我明白这一点,但是我正在清理其他开发人员的一些东西,我通常从最小的更改开始并改进它们。由于某种奇怪的原因,这些都被设置为成员变量,在转换过程中,我开始收到这个奇怪的错误。然后,我将所有内容都大写,使其完全符合预期,并弄清楚发生了什么。这不是关于不正确的代码实践,而是更多关于为什么这个东西正在寻找一个不存在的变量。
  • 您是否为这些字段定义了 getter 和 setter?如果是,请包含 EmployeeId 的对

标签: java json jackson dto objectmapper


【解决方案1】:

答案是, 通常情况下:注意您编写的代码。

getter 和 setter 将字段公开为 m*(其中 * 是实际的字段名称)。

看看这个:

getmEmployeeId(
   ^
   |

这是字母“m”。

因此,这会将字段名称公开为“mEmployeeId”

更多详情:
该方法返回的值与 getter 公开的值的名称无关。 Java 要求 getter 名称的格式为“getFieldName”,并且 该 setter nanes 的格式为“setFieldName” 其中“FieldName”是任何不是方法名称的“get”或“set”部分的值。

这称为“JavaBean 命名约定”,如果您使用 Java 编码并使用任何第三方 Java 库,您绝对必须理解并遵守它。

【讨论】:

  • 那么就可以解释这个问题了。我不知道这是一个要求。我曾计划更改这些名称,但在更改了许多其他代码之后,我想确保在进行更长的重构之前它仍然可以正常工作。没有意识到 setter 和 getter 可能会自己造成这种情况。我认为变量可以被类访问,而不是被类公开。
【解决方案2】:

要将JSON 键与POJO 属性Jackson 匹配使用称为PropertyNamingStrategy 的东西。在您的JSON 中,我们至少可以找到两种策略:

  1. SNAKE_CASEpage_sizeerror_message等)
  2. UPPER_CAMEL_CASEEmployeeIdDepartmentId等)

从另一边POJO类提供第三种策略:

  1. “m”+UPPER_CAMEL_CASEmEmployeeIdmDepartmentId等)

这就是JSONPOJO 不匹配的原因。要使其发挥作用,您需要实施如下所示的新策略:

class MNamingStrategy extends PropertyNamingStrategy {

    @Override
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method,
        String defaultName) {
        return defaultName.substring(1); // remove first `m` letter
    }
}

你可以这样使用:

@JsonNaming(MNamingStrategy.class)
class Clazz {

    private int Id = 11;

    public int getmId() {
        return Id;
    }

    public void setmId(int id) {
        this.Id = id;
    }

    @Override
    public String toString() {
        return "Clazz{" +
            "Id=" + Id +
            '}';
    }
}

从现在开始,您可以将上面的JSON反序列化为给定的POJO

当您使用属性名称添加 @JsonProperty 注释时,您已告诉 Jackson 使用自定义映射。

另见:

  1. Spring Jackson property naming strategy
  2. PropertyNamingStrategy
  3. More Jackson Annotations

【讨论】:

  • 原来我的实际问题是我不知道 Java 直接使用 get 公开了所有内容。我想,getX 返回名称会暴露名称,而不是 X。所以在得知我的问题得到解决之后。我不打算结合所有的命名策略,因为我继承了它以匹配适当的约定,所以这些都被重构了。我的策略是更改变量名称,测试安全,更改函数名称,再次测试。第一次测试失败了,我没有意识到这是因为功能。
  • 这是个好方法。无论如何,我希望我的帖子能帮助你更好地理解这个问题。另外,看看谷歌的代码风格:google.github.io/styleguide/javaguide.html
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-12
  • 2014-09-18
  • 2012-01-19
  • 2012-07-30
  • 1970-01-01
相关资源
最近更新 更多