Подтвердить что ты не робот

Поле указания является переходным для MongoDB, но не для RestController

Я использую spring -boot для обеспечения интерфейса REST, сохраненного MongoDB. Я использую "стандартные" зависимости для его включения, включая spring-boot-starter-data-mongodb и spring-boot-starter-web.

Однако в некоторых моих классах есть поля, которые я аннотирую @Transient, чтобы MongoDB не сохранял эту информацию. Тем не менее, эта информация, которую я хочу отправить в мои службы отдыха. К сожалению, как MongoDB, так и остальные контроллеры, похоже, разделяют эту аннотацию. Поэтому, когда мой front-end получает объект 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/info/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);
    }
}

Как есть, hp и defenses отображаются как 0 и null соответственно. Если я удаляю тег @Transient, он приходит.

4b9b3361

Ответ 1

Я решил с помощью @JsonSerialize. При желании вы также можете выбрать @JsonDeserialize, если вы хотите, чтобы это было также отменено.

@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;
}

Ответ 2

Проблема заключается в том, что как монго, так и джексон ведут себя так, как ожидалось. Mongo не сохраняет данные, и Джексон игнорирует свойство, поскольку он отмечен как переходный. Мне удалось заставить эту работу "обмануть" джексон, чтобы игнорировать переходное поле, а затем аннотировать метод геттера с помощью @JsonProperty. Вот мой пример bean.

    @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;
    }
}

Это скорее работа, чем правильное решение, поэтому я не уверен, что это приведет к возникновению каких-либо побочных эффектов.

Ответ 3

Пока вы используете org.springframework.data.annotation.Transient, он должен работать как ожидалось. Джексон ничего не знает о spring -data и игнорирует его аннотации.

Пример кода, который работает:

interface PersonRepository extends CrudRepository<Person, String> {}
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
class Person {
    @Id
    private String id;
    private String name;
    @Transient
    private Integer age;

    // setters & getters & toString()
}
@RestController
@RequestMapping("/person")
class PersonController {
    private static final Logger LOG = LoggerFactory.getLogger(PersonController.class);
    private final PersonRepository personRepository;

    @Autowired
    PersonController(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @RequestMapping(method = RequestMethod.POST)
    public void post(@RequestBody Person person) {
        // logging to show that json deserialization works
        LOG.info("Saving person: {}", person);
        personRepository.save(person);
    }

    @RequestMapping(method = RequestMethod.GET)
    public Iterable<Person> list() {
        Iterable<Person> list = personRepository.findAll();
        // setting age to show that json serialization works
        list.forEach(foobar -> foobar.setAge(18));

        return list;
    }
}

Выполнение POST http://localhost:8080/person:

{
    "name":"John Doe",
    "age": 40
}
  • Выход журнала Saving person: Person{age=40, id='null', name='John Doe'}
  • Вход в коллекцию person: { "_id" : ObjectId("55886dae5ca42c52f22a9af3"), "_class" : "demo.Person", "name" : "John Doe" } - возраст не сохраняется.

Выполнение GET http://localhost:8080/person:

  • Результат: [{"id":"55886dae5ca42c52f22a9af3","name":"John Doe","age":18}]

Ответ 4

карлос-bribiescas, какую версию вы используете для этого. Это может быть проблема с версией. Потому что эта временная аннотация подразумевается только для того, чтобы не сохраняться в mongo db. Попробуйте изменить версию. Вероятно похож на Maciej one (выпуск 1.2.4).

Возникла проблема с обработкой json для проекта данных spring в одной из версий. http://www.widecodes.com/CyVjgkqPXX/fields-with-jsonproperty-are-ignored-on-deserialization-in-spring-boot-spring-data-rest.html

Ответ 5

Поскольку вы не подвергаете свою MongoRepositories как спокойную конечную точку с Spring Data REST, имеет смысл иметь ваш Resources/endpoint ответы, отделившиеся от вашей модели домена, таким образом, ваша модель домена может развиваться без ущерба для ваших клиентов/потребителей вашего отдыха. Для Ресурса вы можете рассмотреть возможность использования Spring HATEOAS.