Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derived ToJSON1 instance does not respect omitNothingFields = True #687

Closed
ejconlon opened this issue Mar 6, 2019 · 9 comments
Closed
Assignees

Comments

@ejconlon
Copy link

ejconlon commented Mar 6, 2019

For an instance

data C a = C { required :: a, optional :: Maybe a }
    deriving (Eq, Show, Generic1)
    deriving (ToJSON1) via (AesonWrapper1 C)

with a simple deriving via newtype wrapper AesonWrapper1 I am seeing the value C 1 Nothing serialize with null

        Example test case: FAIL
          Repro.hs:77:
          expected: "{\"required\":1}"
           but got: "{\"required\":1,\"optional\":null}"

See https://gist.github.com/ejconlon/30dc50b183a0f72501c3e49ce57cae52 for a self-contained repro.

@Lysxia
Copy link
Collaborator

Lysxia commented Mar 6, 2019

Indeed, it seems that this option currently only works for Generic, not Generic1. One way to fix it would be to add incoherent instances for Rec1, like what is there for K1. But Generic1 is also quite flawed, I wonder whether such a fix is worth maintaining, as opposed to discouraging use of Generic1 altogether (to be clear, I'm not the maintainer, I'm just proposing the idea, with my strongly negative opinion of Generic1).

In particular, ToJSON1 F should be subsumed by forall a. ToJSON a => ToJSON (F a).

Would it work for you to use ToJSON in this way, instead of ToJSON1?

@ejconlon
Copy link
Author

ejconlon commented Mar 6, 2019

I'm really not sure how to do it in a way that's re-usable.

instance (Generic (f a), ToJSON a) => ToJSON (AesonWrapper1 f a) where
    toJSON = genericToJSON options . unAesonWrapper1
    toEncoding = genericToEncoding options . unAesonWrapper1

data C a = C { required :: a, optional :: Maybe a }
    deriving (Eq, Show, Generic)

deriving via (AesonWrapper1 C a) instance (Generic (C a), ToJSON a) => ToJSON (C a)

fails to compile with

Could not deduce (aeson-1.4.2.0:Data.Aeson.Types.ToJSON.GToJSON
                          Value Zero (Rep (f a)))

similarly for Encoding. I really have no idea how to direct derivation of GToJSON and the like.

@Lysxia
Copy link
Collaborator

Lysxia commented Mar 6, 2019

Can you try

-- When going through Generic, maybe you don't need the ...1 variant.
newtype AesonWrapper a = AesonWrapper { unAesonWrapper :: a }

-- You can only solve `GToJSON` and `GToEncoding` constraints for concrete `a`, so as long as it's a type variable, the constraints have to be explicit like this.
instance (Generic a, GToJSON (Rep a), GToEncoding (Rep a)) => ToJSON (AesonWrapper a) where
  ...

-- same as before
data C a = ...

deriving via (AesonWrapper (C a)) instance ToJSON a => ToJSON (C a)
  -- does the "via" go here or at the end?

@ejconlon
Copy link
Author

ejconlon commented Mar 6, 2019

Ah thanks! Yes, you are right I can just use the basic wrapper. (My brain is a little fuzzy at the moment...)

This makes the test pass

data C a = C { required :: a, optional :: Maybe a }
    deriving (Eq, Show, Generic)

deriving via (AesonWrapper (C a)) instance ToJSON a => ToJSON (C a)

Now, I originally switched to ToJSON1 because for fixpoint types like newtype TFix = TFix { unTFix :: T TFix }) Aeson would hang during encoding. I also had some crazy code that could be simplified, though. Let me expand the example and see if that's still the case.

@ejconlon
Copy link
Author

ejconlon commented Mar 6, 2019

Ok, it even seems to work recursively! https://gist.github.com/ejconlon/a017e2dc7f0482c26b0d26b0efd9e22d

My final question: Should we put a warning in the ToJSON1 documentation? I'm not even sure what other options are not respected - null fields are tolerable, but differences in sum encoding are not!

@phadej
Copy link
Collaborator

phadej commented Mar 6, 2019

Problems with Maybe fields are because we do tricks with overlapping instances, everything else (IIRC) is on more solid ground, so should work.

@ejconlon
Copy link
Author

ejconlon commented Mar 7, 2019

What do you think about this warning in the documentation for genericLiftToJSON and genericLiftToEncoding:

Please note that this does not obey the omitNothingFields option of the provided Options. If this is an issue, please derive ToJSON instead of ToJSON1.

@bergmark
Copy link
Collaborator

bergmark commented Mar 14, 2019 via email

@phadej phadej self-assigned this Jun 12, 2023
@phadej
Copy link
Collaborator

phadej commented Jun 12, 2023

With #1039 we should be able to fix ToJSON1 deriving.

I'll add tests for this issue to verify they do.

phadej added a commit that referenced this issue Jun 13, 2023
phadej added a commit that referenced this issue Jun 15, 2023
- Add combinators for using omit* stuff in manually written instances
- Add Manual tests
- Cleanup OptionalFields.Common
- Fix TH and Generics
- Add combinators ToJSON1/2 and FromJSON1/2
- Const, Identity, Tagged and other newtypes
- Fix #687. ToJSON1 respects omitting fields
- Fix #571. Introduce allowOmittedFields to Generics/TH options.
- Resolve #792. () and Proxy can be omitted
phadej added a commit that referenced this issue Jun 15, 2023
- Add combinators for using omit* stuff in manually written instances
- Add Manual tests
- Cleanup OptionalFields.Common
- Fix TH and Generics
- Add combinators ToJSON1/2 and FromJSON1/2
- Const, Identity, Tagged and other newtypes
- Fix #687. ToJSON1 respects omitting fields
- Fix #571. Introduce allowOmittedFields to Generics/TH options.
- Resolve #792. () and Proxy can be omitted
phadej added a commit that referenced this issue Jun 15, 2023
- Add combinators for using omit* stuff in manually written instances
- Add Manual tests
- Cleanup OptionalFields.Common
- Fix TH and Generics
- Add combinators ToJSON1/2 and FromJSON1/2
- Const, Identity, Tagged and other newtypes
- Fix #687. ToJSON1 respects omitting fields
- Fix #571. Introduce allowOmittedFields to Generics/TH options.
- Resolve #792. () and Proxy can be omitted
@phadej phadej closed this as completed in b06eb2c Jun 19, 2023
JonathanLorimer pushed a commit to JonathanLorimer/aeson that referenced this issue Aug 7, 2023
- Add combinators for using omit* stuff in manually written instances
- Add Manual tests
- Cleanup OptionalFields.Common
- Fix TH and Generics
- Add combinators ToJSON1/2 and FromJSON1/2
- Const, Identity, Tagged and other newtypes
- Fix haskell#687. ToJSON1 respects omitting fields
- Fix haskell#571. Introduce allowOmittedFields to Generics/TH options.
- Resolve haskell#792. () and Proxy can be omitted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants