Re: JPA 2.2 API on Maven Central

Steve Ebersole
 

Grr...  

That's fine if you are describing one possible way the spec could be changed.  However that is not how the spec is defined today.  Today, your point (4) is actually defined as "pick one"; and in this "pick one case" it really is undefined which you will get when multiple are available.  From section 9.2...

<quote>
The Persistence bootstrap class must locate all of the persistence providers using the Persis-
tenceProviderResolver mechanism described in section 9.3 and call createEntityMan-
agerFactory on them in turn until an appropriate backing provider returns an
EntityManagerFactory instance. A provider may deem itself as appropriate for the persistence
unit if any of the following are true:
<p/>

It then goes on to enumerate the ways in which a provider is allowed to "deem itself as appropriate for the persistence
unit" as:
  1. Its implementation class has been specified in the provider element for that persistence unit in the persistence.xml file and has not been overridden by a different javax.persistence.provider property value included in the Map passed to the createEntityManagerFactory method.
  2. The javax.persistence.provider property was included in the Map passed to createEntityManagerFactory and the value of the property is the provider’s implementation class.
  3. No provider was specified for the persistence unit in either the persistence.xml or the property map.
In other words, if the PU did not (via <provider/> nor javax.persistence.provider setting) specify the provider to use, then any provider can act as the provider, and in your case (4) the first wins, as opposed to what you suggest which is to throw an exception.  So today, from SE bootstrapping, as user who always wants to use Hibernate you *have to* either:
  1. make sure Hibernate is the only provider jar available on the classpath, or
  2. specify <provider/> for each and every PU, or provide a `javax.persistence.provider` setting each time an EM is created.
I hope we can all agree that (2) is a less-than-ideal.  And as for (1), that's not always possible.  But you are right in that this all boils down to how your (4) case is handled.

I wont get into the whole Maven + artifact manager discussion I had started to get into when I accidentally sent earlier, although I am happy to discuss that with anyone.  Instead I'll just finish up that I think it is important to point out that while Bill describes the ideal case, this was clearly never the intent for JPA... otherwise why does the JPA TCK explicitly:
  1. Require that a JPA API jar be provided, and
  2. Test that that jar "properly" define the contracts as set forth in the spec?
That's a rhetorical question - obviously it wouldn't.  If the intent was to just always use this belssed jar, these tests would be pointless.  Clearly this was the intended design from the get-go.  For those of you without access to the TCK, I guess you'll have to take my word for it - making the TCK publicly available (ideally OSS) is a much more worthwhile change to discuss IMO ;)

Bottom line... while we can debate whether to change this, it is unfortunately a change.  And we have already been told, in regards to other requests for changes, that it is too late for changes to make into this MR :(


On Thu, Aug 10, 2017 at 10:36 AM Steve Ebersole <steve@...> wrote:
>> I naively thought an implementation would be found via java.util.ServiceLoader. As long as one provider is in the class path it would be found etc.
>>
>> I would love to see an example of this (to perhaps understand why ServiceLoader does not work in this case?).  Do you have a link to example source for this Steve?

Did I say that ServiceLoader would not work? ;)  So I can't really give you an example of a case where it won't.  That said, ServiceLoader is not about picking one service or the other; its about finding available ones.  And in fact providers are required to be located via ServiceLoader (must include a META-INF/services/javax.persistence.spi.PersistenceProvider file).
That's not the problem.  The problem is working out which to use.  

As for "JavaSE bootstrapping":
1. if the user has defined <provider> then there is no issue ... use that (as long as it is found).
2. if the user hasn't defined <provider> and there is 1 JPA provider in the CLASSPATH then use that.
3. if the user hasn't defined <provider> and there is 0 JPA provider in the CLASSPATH then throw exception.
4. if the user hasn't defined <provider> and there is more than 1 JPA provider in the CLASSPATH then throw exception inviting them to "specify which one, we have these available".

That's fine if you are describing one possible way the spec could be changed.  However that is not how the spec is defined today.  Today, your point (4) is actually defined as "pick one"; and in this pick one case it really is undefined which you will get when multiple are available.

And we also need to look at the limitations of artifact managers.  I've lobbied Maven for a 

Join jpa-spec@javaee.groups.io to automatically receive all group messages.