One option is to simply treat "Data" as the interface{} (any) type, instead of using your custom structs, and handle the resulting values based on inspection of what actually got unmarshaled. Of course, once you've inspected the data to determine what type it should be you could convert it into the appropriate strong type after the fact.
type Response struct {
Data interface{} `json:"data,omitempty"`
Time int64 `json:"time,omitempty"`
Message string `json:"message,omitempty"`
}
Another option is to embed the "Response" struct into specialized structs that look for your custom types and unmarshal into the appropriate one, assuming you know which one you've got ahead of time:
type BaseResponse struct {
Time int64 `json:"time,omitempty"`
Message string `json:"message,omitempty"`
}
type Response1 struct {
BaseResponse
Data map[string]*CustomStruct1 `json:"data"`
}
type Response2 struct {
BaseResponse
Data map[string]*CustomStruct2 `json:"data"`
}
// etc...
Ultimately, the unmarshaler cannot pick a varying type based on the document that gets unmarshaled, it only deserializes JSON values into structures either defined explicitly by you or into generic ones.
interface{}it works for any type because every type satisfies the requirement of having at least zero methods. Looking at your struct, you might want to get yourTimeandMessagefields through embedding instead and use a separate struct for each response type.