es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Deserialice JSON en una interface con múltiples implementaciones.

Estoy construyendo un sistema de Event Sourcing con muchos eventos.
Necesito deserializar un objeto JSON en uno de los posibles tipos de evento.
Sé que puedo hacer algo como:

type TypedJson struct {
    Type string
    Data json.RawMessage
}

func SerializeJson(event IEvent) []byte {
    data, _:= json.Marshal(event)
    dataType := reflect.TypeOf(event).String()
    typeName := dataType[strings.LastIndex(dataType, ".")+1:]
    typedThing := TypedJson{typeName, data}
    finalJson, _ := json.Marshal(typedThing)
    return finalJson
}

func Deserialize(jsonData []byte) IEvent {
    var event TypedJson
    json.Unmarshal(jsonData, &event)
    switch event.Type {
    case "UserCreated":
        var e UserCreated
        json.Unmarshal(event.Data, &e)
        return e
    case "EmailChanged":
        var e EmailChanged
        json.Unmarshal(event.Data, &e)
        return e
    case ...
    }
}

Pero parece incómodo cuando hay muchos eventos que considerar.
¿Existe un enfoque mejor?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una posible manera de simplificar el proceso de deserialización de un objeto json en uno de varios tipos de eventos posibles es utilizar un mapa de nombres de tipo de evento a los tipos de eventos correspondientes, en lugar de usar una sentencia switch con muchos casos. Esto permite agregar fácilmente nuevos tipos de eventos sin tener que modificar el código de deserialización cada vez. Aquí hay un ejemplo:

    // Definir un mapa de nombres de tipo de evento a tipos de eventos correspondientes
    var eventTypes = map[string]reflect.Type{
        "UserCreated":  reflect.TypeOf(UserCreated{}),
        "EmailChanged": reflect.TypeOf(EmailChanged{}),
        // Agregar otros tipos de eventos aquí
    }
    
    // Función de deserialización que utiliza el mapa para deserializar los datos json en el tipo de evento correcto
    func Deserialize(jsonData []byte) (i IEvent, err error) {
        var typedJson TypedJson
        if err := json.Unmarshal(jsonData, &typedJson); err != nil {
            return nil, err
        }
    
        eventType, ok := eventTypes[typedJson.Type]
        if !ok {
            return nil, fmt.Errorf("tipo de evento desconocido: %s", typedJson.Type)
        }
    
        event := reflect.New(eventType).Interface().(IEvent)
        if err := json.Unmarshal(typedJson.Data, event); err != nil {
            return nil, err
        }
    
        return event, nil
    }
    

    En este ejemplo, definimos un mapa llamado eventTypes que mapea los nombres de cadena de los tipos de eventos a sus tipos de reflexión correspondientes. Luego, en la función Deserialize, usamos este mapa para buscar el tipo de reflexión del evento en función del nombre de tipo en el objeto json. Creamos una nueva instancia del evento utilizando reflexión, lo deserializamos en los datos json y lo devolvemos si es exitoso. Si el tipo no se encuentra en el mapa, devolvemos un error.

    Este enfoque simplifica el código de deserialización y permite una fácil adición de nuevos tipos de eventos en el futuro.

Comments are closed.