Jackson mapper.readValue mit generischem Type

PierreDole

Mitglied
Moin,
ich habe ein Projekt in C# angefangen und bin gerade dabei es in Java fortzuführen. Komme jetzt bei einer Sache nicht weiter. Geht darum ein Json-String in ein Objekt umzuwandeln und das ganze generisch.

Wie übersetzt man diesen Code am besten in Java?
C#:
public static T GetJsonObject<T>(string path)
{
    string json = File.ReadAllText(_directory + path);
    return JsonConvert.DeserializeObject<T>(json);
}

Mein Ansatz sieht so aus:
Java:
public class ReadJson {

    public static <T> T get(String filePath) throws IOException {

        String json = Files.readString(Paths.get(filePath));

        ObjectMapper mapper = new ObjectMapper();
        
        return (T) mapper.readValue(json, new TypeReference<T>() {});
    }
}

Und das hier ist der Aufruf:
Java:
public class Settings
{
    public Api api;
    public Data data;

    public static Settings Load()
    {
        Settings settings = null;
        
        
        try {
            settings = ReadJson.<Settings>get("settings.json");
            
        } catch (IOException e) {

            e.printStackTrace();
        }
        
        return settings;
    }
}

Die Settings Klasse ist ein Teil der Json-Klassenstruktur. Die Load-Klasse passte nirgendwo anders rein, also habe ich sie hier reingetan. Hoffe, das geht so, in C# gings jedenfalls. IntelliJ meldet auch keine Fehler, aber ich bekomme beim Builden eine java.lang.ClassCastException im Aufruf in der Load Klasse (Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class nbaStats.resources.settings.Settings).

Würde mich freuen, wenn mir jemand weiterhelfen kann. :)
 
K

kneitzel

Gast
Da Generics so zur Laufzeit in Java nicht existieren übergibt du als zweiten Parameter ein Class<T> und hast so die Klasse. Und dann gibst Du bei der Nutzung Settings.class als zweiten Parameter an.

Das wäre so mein erster Ansatz.
 

PierreDole

Mitglied
Vielen Dank für deine Antwort. Habe das ausprobiert, wie du es vorgeschlagen hast. Seltsamerweise bekomme ich den gleichen Fehler, obwohl ich die Load Methode in eine andere Klasse verlegt habe.

Der neue Ansatz:
Java:
public class ReadJson {

    @SuppressWarnings("unchecked")
    public static <T> T get(String filePath, Class<T> typeReference) throws IOException {

        String json = Files.readString(Paths.get(filePath));
       
        return (T)new ObjectMapper().readValue(json, typeReference.getClass());
    }
}


Aufruf in der neuen Setup Klasse:
Java:
public class Setup {
   
    public static Settings loadSettings()
    {
        Settings settings = null;
       
       
        try {
            settings = ReadJson.<Settings>get("settings.json", Settings.class);
           
        } catch (IOException e) {

            e.printStackTrace();
        }
       
        return settings;
    }
}

Gleiche Exception, wie beim ersten Mal:
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class nbaStats.resources.settings.Settings

Aber, in der alten Datei:
at nbaStats/nbaStats.resources.settings.Settings.Load(Settings.java:17)

Settings.Load gibt es nicht mehr. Jetzt ist die Frage, stimmt die Implementierung nicht oder hat Eclipse die Änderungen beim Run nicht berücksichtigt?
 

PierreDole

Mitglied
Danke, habs geändert. Bekomme dennoch die gleiche Exception, in der gleichen nicht mehr vorhandenen Methode.

Kann man Eclipse anweisen einen vollständigen Rebuild zu machen?
 

PierreDole

Mitglied
Habs hinbekommen. Naja, zumindest bin ich einen Schritt weiter.

Jetzt bekomme ich die andere Exception, im return der get Methode der ReadJson Klasse:
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make public nbaStats.resources.settings.Settings() accessible: module nbaStats does not "exports nbaStats.resources.settings" to module com.fasterxml.jackson.databind
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make public nbaStats.resources.settings.Settings() accessible: module nbaStats does not "exports nbaStats.resources.settings" to module com.fasterxml.jackson.databind
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280)
at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:189)
at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:182)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.util.ClassUtil.checkAndFixAccess(ClassUtil.java:987)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.impl.CreatorCollector._fixAccess(CreatorCollector.java:276)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.impl.CreatorCollector.setDefaultCreator(CreatorCollector.java:128)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addExplicitConstructorCreators(BasicDeserializerFactory.java:446)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:304)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:223)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:261)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:150)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:591)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4733)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4594)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3548)
at com.fasterxml.jackson.databind@2.12.1/com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3516)
at nbaStats/nbaStats.data.ReadJson.get(ReadJson.java:15)
at nbaStats/nbaStats.Setup.loadSettings(Setup.java:16)
at nbaStats/nbaStats.Main.main(Main.java:37)


Ich hatte den Tab "Problems" übersehen. Da wurden vier Fehler aufgeführt:

Code:
Description    Resource    Path    Location    Type
Project 'NbaStats' is missing required library: 'G:/workspace/_java/NbaStats/Libs/jackson-annotations-2.12.1.jar'    NbaStats        Build path    Build Path Problem
Project 'NbaStats' is missing required library: 'G:/workspace/_java/NbaStats/Libs/jackson-core-2.12.1.jar'    NbaStats        Build path    Build Path Problem
Project 'NbaStats' is missing required library: 'G:/workspace/_java/NbaStats/Libs/jackson-databind-2.12.1.jar'    NbaStats        Build path    Build Path Problem
The project cannot be built until build path errors are resolved    NbaStats        Unknown    Java Problem

Ja, das stimmt. Diese Verzeichnisse existieren nicht unter Linux. :D Gestern habe ich das unter Windows 10 angefangen. Heute bin ich in Linux. Als ich das Projekt in Eclipse geladen habe und sah, daß ObjectMapper von IntelliJ unterstrichen war, dachte ich, ich müsse die Jackson Jars unter Linux auch nochmal einmalig einbinden.
Scheint jetzt doch nicht der Fall zu sein. Er hat nur die gestern unter Windows eingebundenen Jars nicht gefunden. Aber das ist doch irgendwo der tiefere Sinn einer plattformübergreifenden Sprache und auch der Grund, warum ich das Projekt in Java machen will: mal bin ich in Windows, mal in Linux. Werde ich jetzt jedes Mal, wenn ich das OS wechsle, die Paths neu setzen müssen?
 

mrBrown

Super-Moderator
Mitarbeiter
Aber das ist doch irgendwo der tiefere Sinn einer plattformübergreifenden Sprache und auch der Grund, warum ich das Projekt in Java machen will: mal bin ich in Windows, mal in Linux. Werde ich jetzt jedes Mal, wenn ich das OS wechsle, die Paths neu setzen müssen?
Dafür gibt es Build-Tools wie Maven und Gradle, dort gibst du nur an, was du für Dependencies nutzen willst, und das wo und wie übernehmen die dann.
 

PierreDole

Mitglied
Maven ist drauf und ich habe das Project in ein Maven-Project umgewandelt. Die pom.xml habe ich auch bearbeitet. Hoffe, das klappt jetzt. :)

Bei der Exception komme ich aber leider immer noch nicht weiter. Warum ist die Settings Klasse nicht zugreifbar und wie kann ich das ändern?
 

mrBrown

Super-Moderator
Mitarbeiter
Bei der Exception komme ich aber leider immer noch nicht weiter. Warum ist die Settings Klasse nicht zugreifbar und wie kann ich das ändern?
Hat das Projekt eine module-info.java?

Die kannst du entweder löschen (und damit das Module-System "ausschalten"), oder das Module-System nutzen, dann müsstest du dort angeben, dass Jackson auf die Settings-Klasse zugreifen darf, etwa: exports nbaStats.resources.settings to com.fasterxml.jackson.databind
 
K

kneitzel

Gast
Das Problem sind die Modules und das Gute ist, dass bei der Fehlermeldung meist die Lösung mitgegeben wird:
module nbaStats does not "exports nbaStats.resources.settings" to module com.fasterxml.jackson.databind

Also in Deinem module nbaStats ein
exports nbaStats.resources.settings
Hinzufügen.
 

PierreDole

Mitglied
Ja! Jetzt klappts! :) Vielen Dank euch.

Also war mit module die module-info.java gemeint. Sorry, ich lerne das alles erst. :) Mensch, das war ein langer Kampf. Freue mich schon auf morgen. Dann ich ich endlich damit anfangen mein Projekt in Java umzuschreiben. Heute bin ich schon zu müde dafür.
 

Ähnliche Java Themen

Neue Themen


Oben