2017-04-10 4 views
1

Ich möchte die getCustomerFromDTO Methode im folgenden Code verbessern, ich muss eine Struktur von einer Schnittstelle {} erstellen und derzeit muss ich diese Schnittstelle zu Byte [] marshall und dann das Array entpacken zu meiner Struktur - es muss einen besseren Weg geben.Golang Convert Interface {} zu struct

Mein Anwendungsfall ist, dass ich Strukturen über Rabbitmq senden und um sie zu senden, verwende ich diesen allgemeinen DTO-Wrapper, der zusätzliche domänenspezifische Daten über sie hat. Wenn ich den DTO von Hase mq eine Ebene unter der Nachricht erhält, wird die Nachricht zu meinem DTO unmarschalliert und dann muss ich meine Struktur von diesem DTO bekommen.

type Customer struct { 
    Name string `json:"name"` 
} 

type UniversalDTO struct { 
    Data interface{} `json:"data"` 
    // more fields with important meta-data about the message... 
} 

func main() { 
    // create a customer, add it to DTO object and marshal it 
    customer := Customer{Name: "Ben"} 
    dtoToSend := UniversalDTO{customer} 
    byteData, _ := json.Marshal(dtoToSend) 

    // unmarshal it (usually after receiving bytes from somewhere) 
    receivedDTO := UniversalDTO{} 
    json.Unmarshal(byteData, &receivedDTO) 

    //Attempt to unmarshall our customer 
    receivedCustomer := getCustomerFromDTO(receivedDTO.Data) 
    fmt.Println(receivedCustomer) 
} 

func getCustomerFromDTO(data interface{}) Customer { 
    customer := Customer{} 
    bodyBytes, _ := json.Marshal(data) 
    json.Unmarshal(bodyBytes, &customer) 
    return customer 
} 

Antwort

7

Vor dem DTO Deserialisieren, stellen Sie den Data Feld auf den Typ, den Sie erwarten.

type Customer struct { 
    Name string `json:"name"` 
} 

type UniversalDTO struct { 
    Data interface{} `json:"data"` 
    // more fields with important meta-data about the message... 
} 

func main() { 
    // create a customer, add it to DTO object and marshal it 
    customer := Customer{Name: "Ben"} 
    dtoToSend := UniversalDTO{customer} 
    byteData, _ := json.Marshal(dtoToSend) 

    // unmarshal it (usually after receiving bytes from somewhere) 
    receivedCustomer := &Customer{} 
    receivedDTO := UniversalDTO{Data: receivedCustomer} 
    json.Unmarshal(byteData, &receivedDTO) 

    //done 
    fmt.Println(receivedCustomer) 
} 

Wenn Sie nicht die Möglichkeit, das Data Feld auf dem DTO zu initialisieren, bevor es unmarshal ist, können Sie Typ Behauptung nach dem Unmarshalling verwenden. Package encoding/json unamrshals interface{} Typ Werte in eine map[string]interface{}, so würde der Code wie folgt aussehen:

type Customer struct { 
    Name string `json:"name"` 
} 

type UniversalDTO struct { 
    Data interface{} `json:"data"` 
    // more fields with important meta-data about the message... 
} 

func main() { 
    // create a customer, add it to DTO object and marshal it 
    customer := Customer{Name: "Ben"} 
    dtoToSend := UniversalDTO{customer} 
    byteData, _ := json.Marshal(dtoToSend) 

    // unmarshal it (usually after receiving bytes from somewhere) 
    receivedDTO := UniversalDTO{} 
    json.Unmarshal(byteData, &receivedDTO) 

    //Attempt to unmarshall our customer 
    receivedCustomer := getCustomerFromDTO(receivedDTO.Data) 
    fmt.Println(receivedCustomer) 
} 

func getCustomerFromDTO(data interface{}) Customer { 
    m := data.(map[string]interface{}) 
    customer := Customer{} 
    if name, ok := m["name"].(string); ok { 
     customer.Name = name 
    } 
    return customer 
} 
+0

Der DTO Unmarshalling durch ein Paket ich getan und es ist das gleiche für alle empfangenen Nachrichten. In meiner Anwendung erhalte ich bereits eine unmarshalled DTO – Tomas

+0

Und Sie haben nicht die Möglichkeit, dieses Paket zu ändern? ist es 3rd Party? – mkopriva

+0

Ich kann es ändern, aber da es ein Allzweck-Paket zu der Zeit ist, die ich den DTO unmarshal, ich kenne nicht den Typ der Struktur trägt es in seinem Datenfeld – Tomas