简体   繁体   中英

GSON unable to deserialize JSON

I am trying to subscribe to a presence Pusher channel using the pusher-websocket-java library. When I connect the channel I get the following exception:

java.lang.RuntimeException: Unable to invoke no-args constructor for class com.pusher.client.channel.impl.PresenceChannelImpl$Presence. Registering an InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:228)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.pusher.client.channel.impl.PresenceChannelImpl.extractPresenceDataFrom(PresenceChannelImpl.java:168)
at com.pusher.client.channel.impl.PresenceChannelImpl.handleSubscriptionSuccessfulMessage(PresenceChannelImpl.java:96)
at com.pusher.client.channel.impl.PresenceChannelImpl.onMessage(PresenceChannelImpl.java:54)
at com.pusher.client.channel.impl.ChannelManager.onMessage(ChannelManager.java:116)
at com.pusher.client.connection.websocket.WebSocketConnection.handleEvent(WebSocketConnection.java:177)
at com.pusher.client.connection.websocket.WebSocketConnection.access$600(WebSocketConnection.java:27)
at com.pusher.client.connection.websocket.WebSocketConnection$6.run(WebSocketConnection.java:261)
at com.pusher.client.util.Factory$1.run(Factory.java:119)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source) 
Caused by: java.lang.UnsupportedOperationException: Cannot allocate class com.pusher.client.channel.impl.PresenceChannelImpl$Presence
at com.google.gson.internal.UnsafeAllocator$4.newInstance(UnsafeAllocator.java:104)
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:225)
... 16 more

I already tried adding a no-args constructor, but this does not seem to work. I still get the same error. Also I made sure the incoming message to be deserialized is correct.

The exception is thrown when executring the return statement at the following function:

@SuppressWarnings("rawtypes")
private static PresenceData extractPresenceDataFrom(final String message) {
    final String dataString = extractDataStringFrom(message);
    return GSON.fromJson(dataString, Presence.class).presence;
}

This is the Presence class:

private class Presence {
    @SerializedName("presence")
    public PresenceData presence;

    public Presence() {
    }
}

And this is the PresenceData class:

private class PresenceData {
    @SerializedName("count")
    public Integer count;
    @SerializedName("ids")
    public List<String> ids;
    @SerializedName("hash")
    public Map<String, Object> hash;

    public PresenceData() {
    }
}

Just to clarify, I did not write this code myself. However, I do have access to the code to modify it. Does anyone have a clue for solving this error?

Gradle is used to build the.jar file:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.ajoberstar:gradle-git:1.1.0'
    }
}

def getProperty = { property ->
    if (!project.hasProperty(property)) {
        throw new GradleException("${property} property must be set")
    }
    return project.property(property)
}

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'eclipse'
apply plugin: 'org.ajoberstar.github-pages'
apply plugin: 'signing'
apply plugin: 'jacoco'

group = "com.pusher"
version = "2.2.5"
sourceCompatibility = "1.8"
targetCompatibility = "1.8"

ext.sharedManifest = manifest {
    attributes(
        "Created-By"            : 'Pusher',
        'Implementation-Vendor' : 'Pusher',
        'Implementation-Title'  : 'Pusher Java Websocket API Example',
        'Implementation-Version': version,
        'Package'               : 'com.pusher.client.example',
        'Main-Class'            : 'com.pusher.client.example.ExampleApp'
    )
}


repositories {
    mavenLocal()
    jcenter()
}

dependencies {
    compile "com.google.code.gson:gson:2.8.6"
    compile "org.java-websocket:Java-WebSocket:1.5.1"

    testCompile "org.mockito:mockito-all:1.8.5"
    testCompile "org.powermock:powermock-module-junit4:1.4.11"
    testCompile "org.powermock:powermock-api-mockito:1.4.11"

    testImplementation "com.google.truth:truth:1.0.1"
}


processResources {
    filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [
        version: project.version
    ] )
}


javadoc {
    /* info for JavaDoc options http://docs.oracle.com/javase/6/docs/technotes/tools/windows/javadoc.html#overviewcomment */
    title "Pusher Java Websocket API"
    options.overview = file("src/main/javadoc/overview.html")
    // uncomment this to use the custom javadoc styles
    //options.stylesheetFile = file("src/main/javadoc/css/styles.css")
    exclude "com/pusher/client/channel/impl/*"
    exclude "com/pusher/client/connection/impl/*"
    exclude "com/pusher/client/connection/websocket/*"
    exclude "com/pusher/client/crypto/nacl/*"
    exclude "com/pusher/client/util/internal/*"
    exclude "org/java_websocket/*"
    exclude "com/pusher/client/example/*"
    options.linkSource = true
}


jar {
    manifest = project.manifest {
        from sharedManifest
    }
}


task fatJar(type: Jar, dependsOn:configurations.runtime) {
    manifest = project.manifest {
        from sharedManifest
    }
    baseName = project.name + '-with-dependencies'
    from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
    classifier = 'jar-with-dependencies'
}
assemble.dependsOn fatJar


task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}
assemble.dependsOn sourcesJar


task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}
assemble.dependsOn javadocJar


githubPages {
    repoUri = 'https://github.com/pusher/pusher-websocket-java.git'
    pages {
        from javadoc.outputs.files
    }
    commitMessage = "JavaDoc gh-pages for ${version}"
    credentials {
        username = { getProperty("github.username") }
        password = { getProperty("github.password") }
    }
}


signing {
    required { gradle.taskGraph.hasTask("uploadArchives") }
    sign configurations.archives
}

artifacts {
    archives jar, fatJar, sourcesJar, javadocJar
}

task createPublishTarget {
    doLast {
        uploadArchives { repositories { mavenDeployer {
            beforeDeployment {
                MavenDeployment deployment -> signing.signPom(deployment)
            }
            repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
                authentication(
                    userName: getProperty("maven.username"),
                    password: getProperty("maven.password")
                )
            }
            snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
                authentication(
                    userName: getProperty("maven.username"),
                    password: getProperty("maven.password")
                )
            }
            pom.project {
                name 'Pusher Java Client Library'
                packaging 'jar'
                artifactId 'pusher-java-client'
                description 'This is a Java client library for Pusher, targeted at core Java and Android.'
                url 'http://github.com/pusher/pusher-websocket-java'
                scm {
                    connection 'scm:git:git@github.com:pusher/pusher-websocket-java'
                    developerConnection 'scm:git:git@github.com:pusher/pusher-websocket-java'
                    url 'http://github.com/pusher/pusher-websocket-java'
                }
                licenses {
                    license {
                        name 'MIT'
                        url 'https://raw.github.com/pusher/pusher-websocket-java/master/LICENCE.txt'
                        distribution 'https://raw.github.com/pusher/pusher-websocket-java/mvn-repo/'
                    }
                }
                organization {
                    name 'Pusher'
                    url 'http://pusher.com'
                }
                issueManagement {
                    system 'GitHub'
                    url 'https://github.com/pusher/pusher-websocket-java/issues'
                }
                developers {
                    developer {
                        id 'mike'
                        name 'Mike Pye'
                        email 'mike@pusher.com'
                    }
                }
            }
        }}}
    }
}

wrapper {
    gradleVersion = '5.5.1'
}

jacoco {
    toolVersion = "0.8.4"
}

jacocoTestReport {
    reports.xml.enabled = true
    reports.html.enabled = false
    reports.csv.enabled = false
}

// Test Logging - https://stackoverflow.com/a/42425815/2623314
test {
    testLogging {
        showStandardStreams = true
    }
}

I build the project by clicking build->Build Artifacts->Build int intellij. As far as I can tell this is the right way to build a.jar file. Correct me if I'm wrong.

This is the JSON that is being deserialized by the GSON library:

{"event":"pusher_internal:subscription_succeeded","data":"
 {\"presence\":
  {\"count\":1,\"ids\":[\"5\"],\"hash\":
   {\"5\": 
    {\"id\":5,\"name\":\"name\",\"email\":\"test@gmail.com\",
     \"type\":\"bot\",\"botpass\":\"qwerty123\",\"server\":1,\"is_mule\":0,
     \"stage\":\"readybot\",\"is_online\":0,\"email_verified_at\":null,
     \"api_token\":\"TkqRrrZDO5CbLr7y85MAr2qK3wbk2crn6A3PscpPXpE1w\",
     \"created_at\":\"2021-01-28T17:14:00.000000Z\",
     \"updated_at\":\"2021-01-28T17:14:00.000000Z\"
    }
   }
  }
 }
 ","channel":"presence-server.0"
}

You are most likely importing the original Presence class from the pusher-websocket-java library which has no default constructor. com/pusher/client/channel/impl/PresenceChannelImpl.java.Presence

Import your custom Presence class or give it a different name so there is a distinction. Additionally you can use jackson for deserializing which doesn't need a default constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM