Wrapping primitives comes with its own set of problems. Like having to unbox it all the time for things like basic display.
So you either validate it all the time or you unbox it all the time.
Also with dedicated primitives you need to validate the email when you read it from the dB to hydrate it. So you removed couple of validations here but added a couple there.
My solution is stick to basic DTO and validate in the end at the service receiving the data, and let the errors, if any, propagate up the chain in a way that preserves where the input came from. In most cases I validate once.
So this issue we’re talking about. Doesn’t happen.
I guess it depends on how you structure your code.
If you validate at constructor level, then you have this problem. However if you actually parse it, then this will have to be external to the actual class and you are left with a simple Value Object. This means that you can apply constraints only when it makes sense. Most of the time, there is little reason to validate something coming from the DB, so I would rather skip it.
About unboxing, that depends. I would expect for the overall business logic to always use the more structured types, probably this will only be needed once you need to serialize them :)
That's said, if you are happy with your current way, please keep doing it! I would still suggest to give this style a try though :)
So you either validate it all the time or you unbox it all the time.
Also with dedicated primitives you need to validate the email when you read it from the dB to hydrate it. So you removed couple of validations here but added a couple there.
My solution is stick to basic DTO and validate in the end at the service receiving the data, and let the errors, if any, propagate up the chain in a way that preserves where the input came from. In most cases I validate once.
So this issue we’re talking about. Doesn’t happen.