2017-03-24 2 views
2

J'ai un problème avec un code Scala et j'essaye d'exclure un mauvais design de classe (enfin, un constructeur) avant de le traiter comme un problème de réseau.Les constructeurs Scala utilisant val ne fonctionnent pas bien avec le framework de sérialisation

J'ai donc un modèle de classe Scala appelé Hail:

class Hail(val handle : String, val message : String) extends BaseMessage { 
    def this() { 
    this("default_user", "default_message") 
    } 
} 

abstract class BaseMessage extends AbstractMessage(true) { 
} 

// This is a 3rd party open source class written in Java 
public abstract class AbstractMessage implements Message 
{ 
    private transient boolean reliable = true; 

    protected AbstractMessage() 
    { 
    } 

    protected AbstractMessage(boolean reliable) 
    { 
     this.reliable = reliable; 
    } 

    public Message setReliable(boolean f) 
    { 
     this.reliable = f; 
     return this; 
    } 

    public boolean isReliable() 
    { 
     return reliable; 
    } 
} 

// This is also a 3rd party open source class written in Java 
public interface Message 
{ 
    public Message setReliable(boolean f); 

    public boolean isReliable(); 
} 

Lors de l'exécution, les instances de cette classe se sérialisé (en binaire), envoyé sur le fil à un serveur, où ils sont désérialisé (retour en Hail instances) et traitées.

J'ai donc code client qui ressemble à ceci:

val h1 : Hail = new Hail("user1", "Hello!") 
val h2 : Hail = new Hail("user2", "Aloha!") 
val h3 : Hail = new Hail("user3", "Bien venu mes amigos") 

client.send(h1) 
client.send(h2) 
client.send(h3) 

Lorsque le serveur reçoit ces messages, il imprime leurs combos poignée/message à STDOUT. Les messages que je reçois sont les suivants:

Server received a Hail: default_user, default_message 
Server received a Hail: default_user, default_message 
Server received a Hail: default_user, default_message 

Au lieu de ce que j'attendrai:

Server received a Hail: user1, Hello! 
Server received a Hail: user1, Aloha! 
Server received a Hail: user3, Bien venu mes amigos 

Encore une fois, ce pourrait être un réseau/sérialisation/problème côté serveur . Mais avant de descendre cette route, je veux m'assurer que ma classe Hail a été écrite correctement.

La structure de sérialisation que j'utilise requiert tous les messages (tels que Hail) pour avoir des constructeurs sans argument (d'où celui que j'ai fourni ci-dessus). Donc, il me semble que quelque chose ne va pas avec mon autre constructeur, et peut-être que le serveur appelle par défaut le constructeur no-arg car il ne peut pas utiliser autre chose.

Je décompilé ma Hail classe et voir ce qui suit:

@ScalaSignature(bytes="<lots of bytes here omitted for brevity") 
public class Hail 
    extends BaseMessage 
{ 
    private final String handle; 

    public String handle() 
    { 
    return this.handle; 
    } 

    public String message() 
    { 
    return this.message; 
    } 

    public Hail() 
    { 
    this("default_user", "default_message"); 
    } 

    public Hail(String handle, String message) {} 
} 

Tout de suite plusieurs choses me sont curieux/suspect: (! Que l'on souhaite)

  • Bien que je vois un private final String handle, Je ne vois pas de champ private final String message réciproque ...
  • En outre, le 2ème constructeur (public Hail(String handle, String message)) est vide/indéfini. Ceci est probablement la racine de mes problèmes.

Je demande donc, comment puis-je factoriser la source de Hail de telle sorte que le résultat final suivant est bytecode que serait décompilation:

@ScalaSignature(bytes="<lots of bytes here omitted for brevity") 
public class Hail 
    extends BaseMessage 
{ 
    private final String handle; 

    public String handle() 
    { 
    return this.handle; 
    } 

    public String message() 
    { 
    return this.message; 
    } 

    public Hail() 
    { 
    this("default_user", "default_message"); 
    } 

    public Hail(String handle, String message) 
    { 
    this.handle = handle; 
    this.message = message; 
    } 
} 

Toutes les idées?

+1

Veuillez également indiquer 'BaseMessage'. Contient-il le champ 'message'? – Thilo

+1

Merci @Thilo (+1) - J'ai mis à jour la question et fourni la hiérarchie complète des classes. La classe 'AbstractMessage' et l'interface' Message' proviennent d'une bibliothèque tierce. – smeeb

+0

Cette décompilation doit être incomplète en quelque sorte. S'il se réfère à 'this.message', cela devrait être défini quelque part. – Thilo

Répondre

3

Le problème est que le côté serveur sérialiseur utilise le constructeur sans-argument, puis modifie les valeurs des paramètres mutables dans la classe.

Cependant, scala val s ne sont pas mutable, ils sont catégorisés comme final paramètres de votre classe, et en tant que telle ne peut muter.Les objets sont donc instanciés avec les valeurs par défaut, puis conservent ces valeurs, car ils ne peuvent pas être modifiés.

Je recommande d'utiliser un sérialiseur compatible scala, mais une solution plus simple consiste à permettre la mutation des propriétés en les déclarant var s au lieu de val s.