You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@maven.apache.org by Curtis Rueden <ct...@wisc.edu> on 2015/02/04 23:32:23 UTC

Re: Best practice for "optional" dependencies?

Hi Mark,

> I'm working on a project which has an "optional" transitive
> dependency.  That is: we depend on someone else's artifact (let's call
> it A), which itself depends *in some circumstances* on a third
> artifact (from a third source) which I'll call "B".  That is:  if you
> never trigger a certain feature of A then it doesn't really need B.  A
> expresses this by making B a dependency with <scope>provided</scope>.

Wouldn't it make more sense for A to declare the dependency on B as
"<optional>true</optional>" rather than abusing the provided scope?

http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html

> I think that A should use Class.forName to probe for B and (if not
> found) gracefully explain why it cannot perform the requested
> function.

I have historically had a lot of trouble with things done that way. The
problem is that Class.forName is very easy to mess up when custom
ClassLoaders are in use. Personally I think it is better to use a
compile-time dependency, and write the actual direct Java code, catching
ClassNotFoundException in the appropriate places to handle the situation
where the dependency is not present at runtime. Then you lean on the
compiler, and avoid subtle reflection-related bugs and problems. Since the
dependency is declared as <optional>true</optional>, you do not infect
downstream code with the dependency in every case -- instead, people can
choose for themselves whether to use it.

> We are thus faced with a choice: declare a transitive dependency as if
> it were a direct dependency, to support an unusable feature, and leave
> notes all over our POMs to explain why dependency:analyze is wrong and
> you should not remove this dependency; or keep explaining to people
> why they get NoClassDefFoundError when processing some of their files.

Could you work around their design issue by catching NoClassDefFoundError,
and handle the error in a more appropriate way for your users?

Regards,
Curtis

On Thu, Jan 22, 2015 at 10:48 AM, Mark H. Wood <mw...@iupui.edu> wrote:

> I'm working on a project which has an "optional" transitive
> dependency.  That is: we depend on someone else's artifact (let's call
> it A), which itself depends *in some circumstances* on a third
> artifact (from a third source) which I'll call "B".  That is:  if you
> never trigger a certain feature of A then it doesn't really need B.  A
> expresses this by making B a dependency with <scope>provided</scope>.
>
> I feel that this is an abuse of the dependency mechanism, and that
> optional dependencies should not be declared to Maven as dependencies
> at all.  I think that A should use Class.forName to probe for B and
> (if not found) gracefully explain why it cannot perform the requested
> function.  What do you think?
>
> The feature in question is decryption of a file, which is triggered
> when A recognizes an encrypted file, and that is out of our control.
> Decryption requires key material, and in our application there is no
> reasonable opportunity to provide it, so we can't actually make use of
> the decryption function.  We are thus faced with a choice: declare a
> transitive dependency as if it were a direct dependency, to support an
> unusable feature, and leave notes all over our POMs to explain why
> dependency:analyze is wrong and you should not remove this dependency;
> or keep explaining to people why they get NoClassDefFoundError when
> processing some of their files.
>
> --
> Mark H. Wood
> Lead Technology Analyst
>
> University Library
> Indiana University - Purdue University Indianapolis
> 755 W. Michigan Street
> Indianapolis, IN 46202
> 317-274-0749
> www.ulib.iupui.edu
>

Re: Best practice for "optional" dependencies?

Posted by Ron Wheeler <rw...@artifact-software.com>.
On 06/02/2015 6:32 AM, Curtis Rueden wrote:
> Hi Ron,
>
>> Why not just mock the classes and have the mock classes take the
>> appropriate actions when they are called by mistake.
> To clarify my earlier comments: I like your solution here, and agree that
> it would work well in this circumstance. It gives more control than my
> suggestion to catch NoClassDefFoundError, and would only cause problems if
> there might be a downstream project that legitimately wants to include the
> real B for any reason.
But wouldn't they just remove the mock B jar and replace it with the 
real "B" jar at deployment or just not install it if the real "B" is 
already present.
I am assuming that Mark is delivering a product that support both a 
run-time with encryption and a run-time that supports non-encryption 
operation.
I am not completely clear on the business arrangement between Mark's 
company, the consumer and the supplier of  the real "B" so installation 
details are open to discussion.

I was trying to suggest something that would remove the concerns from 
the development side and shift it to the product packaging or 
installation phase where different "B" jars would be present at run-time 
depending on what the end-user wanted/purchased.
I would suggest 3 versions of "B"
1) Full package from the third party providing real encryption (perhaps 
purchased and installed separately by the consumer)
2) Consumer version of the non-encrypted "B" that fails in an 
inoffensive way if called by mistake (as an optional install component 
if the consumer does not have the real "B").
3) Developer version of the non-encrypted "B" that fails with loud 
screaming, personnel insults and threats of total annihilation (and lots 
of logging) when called by mistake, to be used in testing the 
non-encrypted operation.

Ron
>
> My comments were mostly orthogonal to yours, in that:
> A) I think the A project should declare B as an optional dependency, not
> provided; and
> B) I do not think the A project should use reflection to access B, but
> rather let the compiler do its job, and catch ClassNotFoundException to
> handle B being missing.
>
> But neither of those comments are really under the control of Mark's
> project. I just mentioned them because he asked why A wasn't using
> reflection to access B.
>
> Regards,
> Curtis
>
> On Thu, Feb 5, 2015 at 1:11 AM, Ron Wheeler <rw...@artifact-software.com>
> wrote:
>
>> Why not just mock the classes and have the mock classes take the
>> appropriate actions when they are called by mistake.
>> Seems easier to manage and you just provide the right jar at run-time as
>> part of the install or deploy.
>> The developers don't have to worry about dependencies and maven works
>> nicely.
>> You could have a testing mock version that jumps up and down when it is
>> called by mistake so that the programmers know that they missed the test
>> for the option.
>>
>>
>> Ron
>>
>>
>>
>> On 04/02/2015 5:32 PM, Curtis Rueden wrote:
>>
>>> Hi Mark,
>>>
>>>   I'm working on a project which has an "optional" transitive
>>>> dependency.  That is: we depend on someone else's artifact (let's call
>>>> it A), which itself depends *in some circumstances* on a third
>>>> artifact (from a third source) which I'll call "B".  That is:  if you
>>>> never trigger a certain feature of A then it doesn't really need B.  A
>>>> expresses this by making B a dependency with <scope>provided</scope>.
>>>>
>>> Wouldn't it make more sense for A to declare the dependency on B as
>>> "<optional>true</optional>" rather than abusing the provided scope?
>>>
>>> http://maven.apache.org/guides/introduction/introduction-to-optional-and-
>>> excludes-dependencies.html
>>>
>>>   I think that A should use Class.forName to probe for B and (if not
>>>> found) gracefully explain why it cannot perform the requested
>>>> function.
>>>>
>>> I have historically had a lot of trouble with things done that way. The
>>> problem is that Class.forName is very easy to mess up when custom
>>> ClassLoaders are in use. Personally I think it is better to use a
>>> compile-time dependency, and write the actual direct Java code, catching
>>> ClassNotFoundException in the appropriate places to handle the situation
>>> where the dependency is not present at runtime. Then you lean on the
>>> compiler, and avoid subtle reflection-related bugs and problems. Since the
>>> dependency is declared as <optional>true</optional>, you do not infect
>>> downstream code with the dependency in every case -- instead, people can
>>> choose for themselves whether to use it.
>>>
>>>   We are thus faced with a choice: declare a transitive dependency as if
>>>> it were a direct dependency, to support an unusable feature, and leave
>>>> notes all over our POMs to explain why dependency:analyze is wrong and
>>>> you should not remove this dependency; or keep explaining to people
>>>> why they get NoClassDefFoundError when processing some of their files.
>>>>
>>> Could you work around their design issue by catching NoClassDefFoundError,
>>> and handle the error in a more appropriate way for your users?
>>>
>>> Regards,
>>> Curtis
>>>
>>> On Thu, Jan 22, 2015 at 10:48 AM, Mark H. Wood <mw...@iupui.edu> wrote:
>>>
>>>   I'm working on a project which has an "optional" transitive
>>>> dependency.  That is: we depend on someone else's artifact (let's call
>>>> it A), which itself depends *in some circumstances* on a third
>>>> artifact (from a third source) which I'll call "B".  That is:  if you
>>>> never trigger a certain feature of A then it doesn't really need B.  A
>>>> expresses this by making B a dependency with <scope>provided</scope>.
>>>>
>>>> I feel that this is an abuse of the dependency mechanism, and that
>>>> optional dependencies should not be declared to Maven as dependencies
>>>> at all.  I think that A should use Class.forName to probe for B and
>>>> (if not found) gracefully explain why it cannot perform the requested
>>>> function.  What do you think?
>>>>
>>>> The feature in question is decryption of a file, which is triggered
>>>> when A recognizes an encrypted file, and that is out of our control.
>>>> Decryption requires key material, and in our application there is no
>>>> reasonable opportunity to provide it, so we can't actually make use of
>>>> the decryption function.  We are thus faced with a choice: declare a
>>>> transitive dependency as if it were a direct dependency, to support an
>>>> unusable feature, and leave notes all over our POMs to explain why
>>>> dependency:analyze is wrong and you should not remove this dependency;
>>>> or keep explaining to people why they get NoClassDefFoundError when
>>>> processing some of their files.
>>>>
>>>> --
>>>> Mark H. Wood
>>>> Lead Technology Analyst
>>>>
>>>> University Library
>>>> Indiana University - Purdue University Indianapolis
>>>> 755 W. Michigan Street
>>>> Indianapolis, IN 46202
>>>> 317-274-0749
>>>> www.ulib.iupui.edu
>>>>
>>>>
>> --
>> Ron Wheeler
>> President
>> Artifact Software Inc
>> email: rwheeler@artifact-software.com
>> skype: ronaldmwheeler
>> phone: 866-970-2435, ext 102
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
>> For additional commands, e-mail: users-help@maven.apache.org
>>
>>


-- 
Ron Wheeler
President
Artifact Software Inc
email: rwheeler@artifact-software.com
skype: ronaldmwheeler
phone: 866-970-2435, ext 102


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org


Re: Best practice for "optional" dependencies?

Posted by Curtis Rueden <ct...@wisc.edu>.
Hi Ron,

> Why not just mock the classes and have the mock classes take the
> appropriate actions when they are called by mistake.

To clarify my earlier comments: I like your solution here, and agree that
it would work well in this circumstance. It gives more control than my
suggestion to catch NoClassDefFoundError, and would only cause problems if
there might be a downstream project that legitimately wants to include the
real B for any reason.

My comments were mostly orthogonal to yours, in that:
A) I think the A project should declare B as an optional dependency, not
provided; and
B) I do not think the A project should use reflection to access B, but
rather let the compiler do its job, and catch ClassNotFoundException to
handle B being missing.

But neither of those comments are really under the control of Mark's
project. I just mentioned them because he asked why A wasn't using
reflection to access B.

Regards,
Curtis

On Thu, Feb 5, 2015 at 1:11 AM, Ron Wheeler <rw...@artifact-software.com>
wrote:

>
> Why not just mock the classes and have the mock classes take the
> appropriate actions when they are called by mistake.
> Seems easier to manage and you just provide the right jar at run-time as
> part of the install or deploy.
> The developers don't have to worry about dependencies and maven works
> nicely.
> You could have a testing mock version that jumps up and down when it is
> called by mistake so that the programmers know that they missed the test
> for the option.
>
>
> Ron
>
>
>
> On 04/02/2015 5:32 PM, Curtis Rueden wrote:
>
>> Hi Mark,
>>
>>  I'm working on a project which has an "optional" transitive
>>> dependency.  That is: we depend on someone else's artifact (let's call
>>> it A), which itself depends *in some circumstances* on a third
>>> artifact (from a third source) which I'll call "B".  That is:  if you
>>> never trigger a certain feature of A then it doesn't really need B.  A
>>> expresses this by making B a dependency with <scope>provided</scope>.
>>>
>> Wouldn't it make more sense for A to declare the dependency on B as
>> "<optional>true</optional>" rather than abusing the provided scope?
>>
>> http://maven.apache.org/guides/introduction/introduction-to-optional-and-
>> excludes-dependencies.html
>>
>>  I think that A should use Class.forName to probe for B and (if not
>>> found) gracefully explain why it cannot perform the requested
>>> function.
>>>
>> I have historically had a lot of trouble with things done that way. The
>> problem is that Class.forName is very easy to mess up when custom
>> ClassLoaders are in use. Personally I think it is better to use a
>> compile-time dependency, and write the actual direct Java code, catching
>> ClassNotFoundException in the appropriate places to handle the situation
>> where the dependency is not present at runtime. Then you lean on the
>> compiler, and avoid subtle reflection-related bugs and problems. Since the
>> dependency is declared as <optional>true</optional>, you do not infect
>> downstream code with the dependency in every case -- instead, people can
>> choose for themselves whether to use it.
>>
>>  We are thus faced with a choice: declare a transitive dependency as if
>>> it were a direct dependency, to support an unusable feature, and leave
>>> notes all over our POMs to explain why dependency:analyze is wrong and
>>> you should not remove this dependency; or keep explaining to people
>>> why they get NoClassDefFoundError when processing some of their files.
>>>
>> Could you work around their design issue by catching NoClassDefFoundError,
>> and handle the error in a more appropriate way for your users?
>>
>> Regards,
>> Curtis
>>
>> On Thu, Jan 22, 2015 at 10:48 AM, Mark H. Wood <mw...@iupui.edu> wrote:
>>
>>  I'm working on a project which has an "optional" transitive
>>> dependency.  That is: we depend on someone else's artifact (let's call
>>> it A), which itself depends *in some circumstances* on a third
>>> artifact (from a third source) which I'll call "B".  That is:  if you
>>> never trigger a certain feature of A then it doesn't really need B.  A
>>> expresses this by making B a dependency with <scope>provided</scope>.
>>>
>>> I feel that this is an abuse of the dependency mechanism, and that
>>> optional dependencies should not be declared to Maven as dependencies
>>> at all.  I think that A should use Class.forName to probe for B and
>>> (if not found) gracefully explain why it cannot perform the requested
>>> function.  What do you think?
>>>
>>> The feature in question is decryption of a file, which is triggered
>>> when A recognizes an encrypted file, and that is out of our control.
>>> Decryption requires key material, and in our application there is no
>>> reasonable opportunity to provide it, so we can't actually make use of
>>> the decryption function.  We are thus faced with a choice: declare a
>>> transitive dependency as if it were a direct dependency, to support an
>>> unusable feature, and leave notes all over our POMs to explain why
>>> dependency:analyze is wrong and you should not remove this dependency;
>>> or keep explaining to people why they get NoClassDefFoundError when
>>> processing some of their files.
>>>
>>> --
>>> Mark H. Wood
>>> Lead Technology Analyst
>>>
>>> University Library
>>> Indiana University - Purdue University Indianapolis
>>> 755 W. Michigan Street
>>> Indianapolis, IN 46202
>>> 317-274-0749
>>> www.ulib.iupui.edu
>>>
>>>
>
> --
> Ron Wheeler
> President
> Artifact Software Inc
> email: rwheeler@artifact-software.com
> skype: ronaldmwheeler
> phone: 866-970-2435, ext 102
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
> For additional commands, e-mail: users-help@maven.apache.org
>
>

Re: Best practice for "optional" dependencies?

Posted by Ron Wheeler <rw...@artifact-software.com>.
Why not just mock the classes and have the mock classes take the 
appropriate actions when they are called by mistake.
Seems easier to manage and you just provide the right jar at run-time as 
part of the install or deploy.
The developers don't have to worry about dependencies and maven works 
nicely.
You could have a testing mock version that jumps up and down when it is 
called by mistake so that the programmers know that they missed the test 
for the option.


Ron


On 04/02/2015 5:32 PM, Curtis Rueden wrote:
> Hi Mark,
>
>> I'm working on a project which has an "optional" transitive
>> dependency.  That is: we depend on someone else's artifact (let's call
>> it A), which itself depends *in some circumstances* on a third
>> artifact (from a third source) which I'll call "B".  That is:  if you
>> never trigger a certain feature of A then it doesn't really need B.  A
>> expresses this by making B a dependency with <scope>provided</scope>.
> Wouldn't it make more sense for A to declare the dependency on B as
> "<optional>true</optional>" rather than abusing the provided scope?
>
> http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
>
>> I think that A should use Class.forName to probe for B and (if not
>> found) gracefully explain why it cannot perform the requested
>> function.
> I have historically had a lot of trouble with things done that way. The
> problem is that Class.forName is very easy to mess up when custom
> ClassLoaders are in use. Personally I think it is better to use a
> compile-time dependency, and write the actual direct Java code, catching
> ClassNotFoundException in the appropriate places to handle the situation
> where the dependency is not present at runtime. Then you lean on the
> compiler, and avoid subtle reflection-related bugs and problems. Since the
> dependency is declared as <optional>true</optional>, you do not infect
> downstream code with the dependency in every case -- instead, people can
> choose for themselves whether to use it.
>
>> We are thus faced with a choice: declare a transitive dependency as if
>> it were a direct dependency, to support an unusable feature, and leave
>> notes all over our POMs to explain why dependency:analyze is wrong and
>> you should not remove this dependency; or keep explaining to people
>> why they get NoClassDefFoundError when processing some of their files.
> Could you work around their design issue by catching NoClassDefFoundError,
> and handle the error in a more appropriate way for your users?
>
> Regards,
> Curtis
>
> On Thu, Jan 22, 2015 at 10:48 AM, Mark H. Wood <mw...@iupui.edu> wrote:
>
>> I'm working on a project which has an "optional" transitive
>> dependency.  That is: we depend on someone else's artifact (let's call
>> it A), which itself depends *in some circumstances* on a third
>> artifact (from a third source) which I'll call "B".  That is:  if you
>> never trigger a certain feature of A then it doesn't really need B.  A
>> expresses this by making B a dependency with <scope>provided</scope>.
>>
>> I feel that this is an abuse of the dependency mechanism, and that
>> optional dependencies should not be declared to Maven as dependencies
>> at all.  I think that A should use Class.forName to probe for B and
>> (if not found) gracefully explain why it cannot perform the requested
>> function.  What do you think?
>>
>> The feature in question is decryption of a file, which is triggered
>> when A recognizes an encrypted file, and that is out of our control.
>> Decryption requires key material, and in our application there is no
>> reasonable opportunity to provide it, so we can't actually make use of
>> the decryption function.  We are thus faced with a choice: declare a
>> transitive dependency as if it were a direct dependency, to support an
>> unusable feature, and leave notes all over our POMs to explain why
>> dependency:analyze is wrong and you should not remove this dependency;
>> or keep explaining to people why they get NoClassDefFoundError when
>> processing some of their files.
>>
>> --
>> Mark H. Wood
>> Lead Technology Analyst
>>
>> University Library
>> Indiana University - Purdue University Indianapolis
>> 755 W. Michigan Street
>> Indianapolis, IN 46202
>> 317-274-0749
>> www.ulib.iupui.edu
>>


-- 
Ron Wheeler
President
Artifact Software Inc
email: rwheeler@artifact-software.com
skype: ronaldmwheeler
phone: 866-970-2435, ext 102


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@maven.apache.org
For additional commands, e-mail: users-help@maven.apache.org