Teaching-projects / SOE-SZTA-2021-Tuti-a-moodle

0 stars 0 forks source link

JsonDeserializer #15

Closed Keelorath closed 3 years ago

Keelorath commented 3 years ago

Ehhez az JsonDeserializerhez kellek írni egy Serializert is vagy az entity/hero felel meg annak?

vadalf commented 3 years ago

Neked csak JsonDeserializer kell, ugyanis ez az alkalmazás nem fog adatot JSON-ként kiírni, legalábbis egyelőre.

EntityBuilder az kuka. Entity osztályról JsonDeserialize kuka.

Kell egy EntityDeserializer, ami képes megállapítani, hogy a JSON Entity-t vagy egy öröklő osztályt reprezentál.
Ez után pedig regisztrálni kell egy SimpleModule-t az ObjectMapper-ben, ami megadja Entity osztályhoz a EntityDeserializer osztályt, mint deserializer.

vadalf commented 3 years ago

@tmRobi ez majd neked is érdekes lehet, ugyanis a GUI is fog olvasni JSON-t, így a te osztályodnak DI-vel kell átadni egy ObjectMapper példányt, ami a fentiek alapján össze van rakva.

Keelorath commented 3 years ago

Ez a JsonDeserializer volt órán? Mert kb 3. pédával felvázolt dokumentációt olvasom róla és mindegyik máshogy csinálja.

vadalf commented 3 years ago

JsonDeserializer Jackson-ból jön.

public class EntityDeserializer extends JsonDeserializer<Entity> {
    @Override
    public Entity deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException {

        var object = p.getCodec().<ObjectNode>readTree(p);
        // ...
    }
}

Valahol Main-ben:

var deserialization = new SimpleModule();
deserialization.addDeserializer(Entity.class, new EntityDeserializer());
objectMapper.registerModule(deserialization);

Mindezt persze úgy, hogy Dependency Injection barátságos legyen a dolog.

Keelorath commented 3 years ago

Bástya, itt a deserialize függvényben visszatérési értéknél valami ilyesminek kéne lenni?

if(isHero(object)== true){
            return Hero(
                health,
                attack,
                defense,
                cooldown,
                name,
                lore,
                xpPerLevel,
                dmgIncreacePerLevel,
                hpIncreasePerLevel,
                cooldownMultiplierPerLevel
                );
        } else {
            return Entity(
                health,
                attack,
                defense,
                cooldown,
                name,
                lore
            );
        }
vadalf commented 3 years ago

Érdemesebb lenne metódusokba belepakolni a típus specifikus kódot, és akkor tudod, hogy abban a metódusban csak azzal a típussal kell foglalkoznod:

return isHero(object) ? buildHero(object) : buildEntity(object);
private Hero buildHero(ObjectNode object) {
    // csak Hero kód
}

private Entity buildEntity(ObjectNode object) {
    // csak Entity kód
}

Esetleg a kód duplikáció elkerülése érdekében még azt lehet csinálni, hogy Entity mindenképpen készül, és ha megvannak a Hero mezői is, akkor az entity példányt "kibelezve" csak hozzárakjuk azokat az extra mezőket a konstruktor meghívásánál.

Keelorath commented 3 years ago

Meg tudtam oldani, viszont sírt azért, hogy Herot nem tud returnölni. Megváltoztathatom a buildHero function-t de akkor hogy néz az már ki. Mert ugye maga a deserializer is Entity. ''' public Entity deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {

    var object = p.getCodec().<ObjectNode>readTree(p);

    return isHero(object) ? buildHero(object) : buildEntity(object);
}

private boolean isHero(ObjectNode object) {
    Integer count = Arrays.stream(heroFields).reduce(0, (c, field)->c + (object.has(field)?1:0),(a,b)->a+b) ;

    if(count == 0){
        return false;
    } else if (count == heroFields.length){
        return true;
    }
    throw new IllegalStateException("ide majd valmi kell még testya!");
}

private Hero buildHero(ObjectNode object){
    buildEntity(object);
    int xpPerLevel = object.get("xp_per_level").asInt();
    int dmgIncreacePerLevel = object.get("dmg_increase_per_level").asInt();
    int hpIncreasePerLevel = object.get("hp_increase_per_level").asInt();
    float cooldownMultiplierPerLevel = object.floatValue();
}

private Entity buildEntity(ObjectNode object){
    double health = object.get("health").asDouble();
    double attack = object.get("attack").asDouble();
    double defense = object.get("defense").asDouble();
    double cooldown = object.get("cooldown").asDouble();
    String name= object.get("name").asText();
    String lore= object.get("lore").asText();
}

'''

Keelorath commented 3 years ago

Nem találja a buld metódusokat az objectmapper. Van ötleted miért nem?

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Builder class `EntityDeserializer` does not have build method (name: 'build')
 at [Source: (File); line: 1, column: 1]
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
        at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder.buildBuilderBased(BeanDeserializerBuilder.java:429)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBuilderBasedDeserializer(BeanDeserializerFactory.java:360)
        at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBuilderBasedDeserializer(BeanDeserializerFactory.java:169)
        at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:342)
        at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
        at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
        at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
        at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
        at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4733)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4594)
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3413)
        at Main.main(Main.java:24)