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

Provide access to Guice's own internal TypeConverters #436

Closed
gissuebot opened this issue Jul 7, 2014 · 31 comments

Comments

@gissuebot
Copy link

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 10, 2009 11:28:36

Guice lets you provide your own type converters using:

  Binder.convertToTypes(matcher, typeConverter);

Original issue: http://code.google.com/p/google-guice/issues/detail?id=436

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 10, 2009 08:35:31

(whoops, accidentally hit return!)

OK, so Guice lets you provide your own type converters using:

  Binder.convertToTypes(matcher, typeConverter);

but there's no way to get access to Guice's own type converters for primitive types.
Having access to these primitive type converters would make it much easier to write
composite-style type converters (think of XStream).

Summary: Provide access to Guice's own internal TypeConverters
Owner: ---

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on October 10, 2009 09:37:27

If you'd like to submit a patch that adds these constants to the interface, that would
be quite reasonable:
  public static final TypeConverter BOOLEAN_CONVERTER;
  public static final TypeConverter SHORT_CONVERTER;
  public static final TypeConverter INTEGER_CONVERTER;
  public static final TypeConverter LONG_CONVERTER;
  public static final TypeConverter FLOAT_CONVERTER;
  public static final TypeConverter DOUBLE_CONVERTER;
  public static final TypeConverter CHARACTER_CONVERTER;
  public static final TypeConverter STRING_CONVERTER;
  public static final TypeConverter ENUM_CONVERTER;
  public static final TypeConverter CLASS_CONVERTER;
You'll need to expose them from TypeConverterBindingProcessor, which should be
just fine. Or move them.

Note that Guice's type conversion facility isn't really general-purpose; I suspect our
performance will be quite horrible if you exceed say, a thousand convertible types
(because we always ask all converters whether they can convert a value).

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 11, 2009 21:08:22

OK, will try out a few options and attach the best patch. The approach I'm using has
a handful of type converters and I combine them to cover a much wider range of types,
so performance should be OK (but I'll watch out for any bottlenecks).

Owner: mcculls

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 12, 2009 03:34:08

I took a slightly different approach, and added a "convertConstant" method to the
injector. This is simpler than exposing the individual primitive type converters.

I've attached a proposed patch of the various changes, but need to add unit tests.

Attachment: gist
   GUICE_ISSUE_436_20091012.txt

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on October 12, 2009 16:06:33

I gotta reject this patch because it overreaches the Guice injector to become a general
type conversion tool. We actually have a full type converter framework that's built
upon Guice, but it's currently Google proprietary. Like a solid framework, that
converter architecture is fully typesafe (it doesn't return Object instances), it supports
lots of target types (protobuffers, possibly DOM elements), plus polymorphism and
composition.

I'd like to avoid supporting weak converters when I know that it's insufficient for
general purpose use.

That said, there is a market for a general purpose type converter framework. I'm not
sure whether ours is worthy of open sourcing, or if we have the manpower to do so.

Status: Invalid
Cc: mikeward.norcal

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 12, 2009 22:04:31

> I gotta reject this patch because it overreaches the Guice injector to become
> a general type conversion tool.

That's disappointing, without this patch I'll have to duplicate functionality already
contained inside Guice because it's not available via an external API.
(I'm working on replacing Plexus type conversion with a Guice-driven solution.)

BTW, here's how I came up with this patch...

Your original suggestion was to simply expose the ~10 internal type converter
implementations as constant objects on the API. IMHO this would lead to tight
coupling and make it harder to change the set of converters provided by Guice.

I considered adding an API/SPI to list/query the installed set of type converters
including the internal set (like you can do with all bindings, incl. just-in-time)
but clients would still be using the raw TypeConverter API which is not type-safe.
They would also be duplicating the lookup+checking already done by the Injector.

Therefore I decided to provide a type-safe "convertConstant" method, which linked the
required type and return value. The injector already has code to find the right
converter and check the converted value is of the right type, so this is really just
a bit of refactoring and a new method to allow clients to request the same sort of
conversions as done by the injector itself.

> We actually have a full type converter framework that's built upon Guice, but
> it's currently Google proprietary. Like a solid framework, that converter
> architecture is fully typesafe (it doesn't return Object instances), it
> supports lots of target types (protobuffers, possibly DOM elements), plus
> polymorphism and composition.

Hehe, knowing there's a great proprietary system out there isn't much comfort ;)

> I'd like to avoid supporting weak converters when I know that it's insufficient
> for general purpose use.

Sure, but this is really just allowing clients to apply the same conversions that
Guice applies internally to satisfy constant bindings. We're not adding additional
logic to the Injector, merely exposing the constant conversion feature to clients.

> That said, there is a market for a general purpose type converter framework.
> I'm not sure whether ours is worthy of open sourcing, or if we have the manpower
> to do so.

Unfortunately I'm on a tight schedule. We were hoping to replace Plexus completely
with Guice, but it looks like we may have to keep the Plexus type conversion system
around, or swap in something like XStream. Then again I could do a simple copy-paste
of the bits I need (although I hate duplicating code) or maintain a patched build of
Guice for our own use (which I also hate doing).

Oh well, back to the drawing board...

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 15, 2009 08:11:46

FYI, decided to use a locally patched build for now as this feature also lets us use
type converters contributed by users. Without this patch they would need to register
their converters first with Guice (for the injector) and second with our extension.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on October 15, 2009 08:55:43

Would it work if Injector had an SPI method to get the full set of registered type
converters? I don't mind doing that:
  public Set<TypeConverterBinding> getTypeConverterBindings()

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 15, 2009 09:04:14

Sure, that would be acceptable. I thought providing a "convertConstant" method would
be less disruptive as it's just exposing existing internal functionality. But an SPI
method is probably the more correct solution, as you can already query other bindings.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 15, 2009 10:05:17

I'll try to whip up a patch tonight to add getTypeConverterBindings()

Status: Accepted

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 15, 2009 11:04:17

Hmm... looks like adding a "getTypeConverterBindings()" method will be a much larger
patch because TypeConverterBinding has a package-private constructor. This means we
would either have to maintain two separate lists in State (one TypeConverterBindings
from external modules and one internal MatcherAndConverters) or find some way to get
the internal converters into TypeConverterBinding elements.

Any suggestions? My gut still suggests the "convertConstant" approach is safer...

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on October 15, 2009 18:48:01

I'd like to expose the TypeConverterBinding, even if we need to make its constructor
more public. I don't mind if that requires us to create TypeConverterBindings for the
built-in converters.

Another benefit of this approach is that we could get ConvertedConstantBinding to
expose the converter that they used.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 16, 2009 01:53:22

New patch that adds getTypeConverterBindings() to the injector and exposes the type
converter used in ConvertedConstantBinding. I also added javax.inject and the TCK to
the test launcher in build.xml, as this is needed to run tests on the command line.

Couple of points about the patch:

  1. used List instead of Set to match other existing methods on the injector.

  2. converted TypeConverterBinding to an interface, which is then implemented inside
    the internal package. This should maintain compatibility with clients while limiting
    access to the constructor.

  3. made sure getScopeBindings() and getTypeConverterBindings() return unmodifiable
    collections.

Attachment: gist
   GUICE_ISSUE_436_20091016.txt

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on October 28, 2009 03:35:10

Passing issue to Jesse for review, latest patch works fine for my use-case.

Owner: limpbizkit
Labels: Milestone-Release2.1

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on March 10, 2010 00:00:17

Simplified patch that just makes the TypeConverterBinding constructor public (better
binary compatibility).

Attachment: gist
   GUICE_ISSUE_436_20100309.txt

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on May 04, 2010 01:23:25

Description

This patch (GUICE_ISSUE_436_20100504.patch) exposes a new method in the Injector:

   List<TypeConverterBinding> getTypeConverterBindings();

which returns the list of type converters registered with the injector, including
internal converters registered by Guice. It also adds a method to the converted
constant binding in the SPI:

   TypeConverterBinding getTypeConverterBinding();

which lets you find out which type converter was used to convert that constant.

Implementation

This patch makes TypeConverterBinding public and uses this as a replacement for the
internal MatcherAndConverter (which was basically a clone of TypeConverterBinding).
It also contains a NPE fix to the Errors.appliesTo() method and makes sure that the
collection views returned from the injector are immutable.

Owner: sberlin

Attachment: gist
   GUICE_ISSUE_436_20100504.patch

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on May 04, 2010 04:27:27

(No comment was entered for this change.)

Labels: -Type-Enhancement Type-Patch

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on June 30, 2010 20:42:52

Any chance this feature could go into 3.0? We've found it useful at Sonatype.

Labels: -Milestone-Release2.1 3.0

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 17, 2010 15:31:48

Any update on if/when this patch will make it into Guice 3?

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 17, 2010 15:40:54

Updated patch that can be cleanly applied against latest trunk

Attachment: gist
   GUICE_ISSUE_436_20101117.patch

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From sberlin on November 17, 2010 20:02:18

I'm personally inclined to leave this particular one out of guice3, primarily because it exposes more of the internal API.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 18, 2010 03:09:46

Where does it expose the internal API? The intent of this patch is to extend the SPI to allow clients to introspect and discover what converters are registered with the injector and find out which converter converted a particular value (both valuable features if you want to know what's going on wrt. value conversion).

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From sberlin on November 18, 2010 05:03:39

Mainly in that it exposes a TypeConverterBinding instance, but looking up in the comments it appears Jesse's OK with that.  I'll try to grab his ear to talk to him.

Also, a question: The patch changes Errors.Converter.appliesTo to add a null check for 'o', which seems to be used in the Errors.convert method.  When would someone want to convert 'null'?  Why would we want to ignore it (as a potential source of mistake/failure)?  I didn't see any obvious places looking in the caller where null was acceptable.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 18, 2010 06:30:52

You'll see the NPE issue whenever you report a custom error message that includes a null parameter.

For example:

   String value = null;
   //...
   binder.addError("Some error, value=%s", value);

Won't actually add the error message to the final output, but instead you'll see an NPE stack trace below it:

Caused by: java.lang.NullPointerException
        at com.google.inject.internal.Errors$Converter.appliesTo(Errors.java:612)
        at com.google.inject.internal.Errors.convert(Errors.java:646)
        at com.google.inject.internal.Errors.format(Errors.java:503)
        at com.google.inject.spi.Elements$RecordingBinder.addError(Elements.java:241)
        at com.google.inject.AbstractModule.addError(AbstractModule.java:125)

which then hides the original message.

It should be possible to use null values in error messages hence the null check.

[ this is also related to Issue 432 : https://code.google.com/p/google-guice/issues/detail?id=432 ]

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on November 18, 2010 08:28:48

I'm okay with the proposed change but like Sam I'm slightly anxious about the change in behaviour around errors.

I also think Set is the right type rather than List, because order is not significant and because each type converter can exist only once.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 18, 2010 08:37:08

Wrt. the Errors change - what if I (as a user) want to add a binder error message that contains a potentially null message parameter? ie. like binder.addError("Some error, value=%s", value); where value might possibly be null.

This is not an unusual situation, but at the moment this will cause an NPE inside the format conversion code in Guice, wiping out the original error message and replacing it with a misleading stack trace that suggests the problem lies inside Guice rather than the true cause.

This is also inconsistent with the javadoc for Binder.addError() which states that String.format() will be used to format the message, and String.format() can handle null message parameters whereas currently Errors cannot.

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 18, 2010 08:41:18

Wrt. List vs Set - I'm fine with it using Set

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From limpbizkit on November 18, 2010 18:14:42

@mcculls - null in that scenario makes sense to me. Sounds like we're good!

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From sberlin on November 18, 2010 18:20:37

SGTM, will patch this in...

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From sberlin on November 18, 2010 18:40:44

committed in r1376 & minor followup in r1377 .  thanks very much, Stuart!

Status: Fixed

@gissuebot

This comment has been minimized.

Copy link
Author

@gissuebot gissuebot commented Jul 7, 2014

From mcculls on November 19, 2010 09:37:14

Excellent, thanks!

@gissuebot gissuebot closed this Jul 7, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.