Java 指定字段对于MongoDB是暂时的,但对于RestController不是
我使用SpringBoot提供了一个与MongoDB持久化的REST接口。我正在使用“标准”依赖项为它供电,包括Java 指定字段对于MongoDB是暂时的,但对于RestController不是,java,spring,mongodb,rest,spring-boot,Java,Spring,Mongodb,Rest,Spring Boot,我使用SpringBoot提供了一个与MongoDB持久化的REST接口。我正在使用“标准”依赖项为它供电,包括springbootstarterdatamongodb和springbootstarterweb 但是,在我的一些类中,我对字段进行了注释@Transient,这样MongoDB就不会保留这些信息。但是,我确实希望在rest服务中发送这些信息。不幸的是,MongoDB和rest控制器似乎都共享该注释。因此,当我的前端接收到JSON对象时,这些字段没有实例化(但仍然声明)。删除注释允许
springbootstarterdatamongodb
和springbootstarterweb
但是,在我的一些类中,我对字段进行了注释@Transient
,这样MongoDB就不会保留这些信息。但是,我确实希望在rest服务中发送这些信息。不幸的是,MongoDB和rest控制器似乎都共享该注释。因此,当我的前端接收到JSON对象时,这些字段没有实例化(但仍然声明)。删除注释允许字段通过JSON对象
我如何分别为MongoDB和REST配置什么是瞬态的
这是我的班级
package com.clashalytics.domain.building;
import com.clashalytics.domain.building.constants.BuildingConstants;
import com.clashalytics.domain.building.constants.BuildingType;
import com.google.common.base.Objects;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import java.util.*;
public class Building {
@Id
private int id;
private BuildingType buildingType;
private int level;
private Location location;
// TODO http://stackoverflow.com/questions/30970717/specify-field-is-transient-for-mongodb-but-not-for-restcontroller
@Transient
private int hp;
@Transient
private BuildingDefense defenses;
private static Map<Building,Building> buildings = new HashMap<>();
public Building(){}
public Building(BuildingType buildingType, int level){
this.buildingType = buildingType;
this.level = level;
if(BuildingConstants.hpMap.containsKey(buildingType))
this.hp = BuildingConstants.hpMap.get(buildingType).get(level - 1);
this.defenses = BuildingDefense.get(buildingType, level);
}
public static Building get(BuildingType townHall, int level) {
Building newCandidate = new Building(townHall,level);
if (buildings.containsKey(newCandidate)){
return buildings.get(newCandidate);
}
buildings.put(newCandidate,newCandidate);
return newCandidate;
}
public int getId() {
return id;
}
public String getName(){
return buildingType.getName();
}
public BuildingType getBuildingType() {
return buildingType;
}
public int getHp() {
return hp;
}
public int getLevel() {
return level;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public BuildingDefense getDefenses() {
return defenses;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Building building = (Building) o;
return Objects.equal(id, building.id) &&
Objects.equal(hp, building.hp) &&
Objects.equal(level, building.level) &&
Objects.equal(buildingType, building.buildingType) &&
Objects.equal(defenses, building.defenses) &&
Objects.equal(location, building.location);
}
@Override
public int hashCode() {
return Objects.hashCode(id, buildingType, hp, level, defenses, location);
}
}
package com.clashalytics.domain.building;
导入com.clashalytics.domain.building.constants.BuildingConstants;
导入com.clashalytics.domain.building.constants.BuildingType;
导入com.google.common.base.Objects;
导入org.springframework.data.annotation.Id;
导入org.springframework.data.annotation.Transient;
导入java.util.*;
公共班级大楼{
@身份证
私有int-id;
私有BuildingType BuildingType;
私有整数级;
私人位置;
//待办事项http://stackoverflow.com/questions/30970717/specify-field-is-transient-for-mongodb-but-not-for-restcontroller
@短暂的
私人int hp;
@短暂的
私人建筑防御工事;
私有静态映射建筑=新HashMap();
公共建筑(){}
公共建筑(建筑类型建筑类型,内部级别){
this.buildingType=buildingType;
这个水平=水平;
if(BuildingConstants.hpMap.containsKey(buildingType))
this.hp=BuildingConstants.hpMap.get(buildingType.get)(级别-1);
this.defenses=BuildingDefense.get(buildingType,level);
}
公共静态建筑get(建筑类型市政厅,内部层){
建筑新候选人=新建筑(市政厅,楼层);
if(建筑物、集装箱(新候选者)){
返回建筑物。获取(新候选);
}
建筑物。放置(新候选,新候选);
返回新的候选人;
}
公共int getId(){
返回id;
}
公共字符串getName(){
返回buildingType.getName();
}
公共BuildingType getBuildingType(){
返回buildingType;
}
公共int getHp(){
返回hp;
}
public int getLevel(){
回报水平;
}
公共位置getLocation(){
返回位置;
}
公共无效设置位置(位置){
这个位置=位置;
}
公共建筑防御系统{
返回防御;
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
建筑物=(建筑物)o;
返回Objects.equal(id,building.id)&&
Objects.equal(hp,building.hp)&&
对象。相等(标高,建筑物。标高)&&
Objects.equal(buildingType,building.buildingType)&&
对象。相等(防御,建筑。防御)&&
对象。相等(位置,建筑。位置);
}
@凌驾
公共int hashCode(){
返回Objects.hashCode(id、buildingType、hp、级别、防御、位置);
}
}
按原样,
hp
和防御
分别显示为0
和null
。如果我删除@Transient
标记,它就会出现。您的问题似乎是mongo和jackson的行为都与预期相符。Mongo不会持久化数据,jackson会忽略该属性,因为它被标记为瞬态。我通过“欺骗”jackson忽略瞬态字段,然后用@JsonProperty
注释getter方法,成功地实现了这一点。这是我的样本豆
@Entity
public class User {
@Id
private Integer id;
@Column
private String username;
@JsonIgnore
@Transient
private String password;
@JsonProperty("password")
public String getPassword() {
return // your logic here;
}
}
这与其说是一个合适的解决方案,不如说是一个变通办法,所以我不确定这是否会给您带来任何副作用。只要您使用
org.springframework.data.annotation.Transient
它就应该可以正常工作。Jackson对spring数据一无所知,它忽略了它的注释
示例代码,有效:
interface PersonRepository extends CrudRepository<Person, String> {}
- 日志输出
Saving person:person{age=40,id='null',name='John Doe'}
集合中的条目:person
-年龄不会持久化{“_id”:ObjectId(“55886dae5ca42c52f22a9af3”),“_类”:“demo.Person”,“name”:“John Doe”}
http://localhost:8080/person
:
{
"name":"John Doe",
"age": 40
}
- 结果:
[{“id”:“55886dae5ca42c52f22a9af3”,“姓名”:“John Doe”,“年龄”:18}]
由于您没有将您的
MongoRepositories
公开为restful端点,因此将资源/端点
响应与域模型分离更有意义,这样您的域模型就可以在不影响rest客户机/消费者的情况下发展。对于资源,你可以考虑利用什么来提供。 < P>我用<强> @ JSONSerialIt/Stult>解决了。如果您还希望反序列化,还可以选择@jsondeselliate
@Entity
public class Article {
@Column(name = "title")
private String title;
@Transient
@JsonSerialize
@JsonDeserialize
private Boolean testing;
}
// No annotations needed here
public Boolean getTesting() {
return testing;
}
public void setTesting(Boolean testing) {
this.testing = testing;
}
我通过实现定制的JacksonAnnotationIntrospector解决了这个问题:
@Bean
@Primary
ObjectMapper objectMapper() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
AnnotationIntrospector annotationIntrospector = new JacksonAnnotationIntrospector() {
@Override
protected boolean _isIgnorable(Annotated a) {
boolean ignorable = super._isIgnorable(a);
if (ignorable) {
Transient aTransient = a.getAnnotation(Transient.class);
JsonIgnore jsonIgnore = a.getAnnotation(JsonIgnore.class);
return aTransient == null || jsonIgnore != null && jsonIgnore.value();
}
return false;
}
};
builder.annotationIntrospector(annotationIntrospector);
return builder.build();
}
这段代码使org.springframework.data.annotation.Transientannotation对Jackson
不可见,但对mongodb有效
@Entity
public class Article {
@Column(name = "title")
private String title;
@Transient
@JsonSerialize
@JsonDeserialize
private Boolean testing;
}
// No annotations needed here
public Boolean getTesting() {
return testing;
}
public void setTesting(Boolean testing) {
this.testing = testing;
}
@Bean
@Primary
ObjectMapper objectMapper() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
AnnotationIntrospector annotationIntrospector = new JacksonAnnotationIntrospector() {
@Override
protected boolean _isIgnorable(Annotated a) {
boolean ignorable = super._isIgnorable(a);
if (ignorable) {
Transient aTransient = a.getAnnotation(Transient.class);
JsonIgnore jsonIgnore = a.getAnnotation(JsonIgnore.class);
return aTransient == null || jsonIgnore != null && jsonIgnore.value();
}
return false;
}
};
builder.annotationIntrospector(annotationIntrospector);
return builder.build();
}