As I wait on the beta6 release process to complete so that Ralph can commit my 
first pass at the JDBC, JPA, and NoSQL Appenders, I wanted to start a 
discussion about the JPA appender and JPA 2.1. (For reference, you can see the 
new feature request here [1], and there is a patch attached to that feature 
request containing my first pass at the Appenders.)

Currently, the patch includes a JPA appender that requires JPA 2.0. Hibernate 
isn't the only JPA provider out there, but since it's the most popular I'll use 
it as an example here. Hibernate 3.5.0 or higher is required for JPA 2.0 
support. JPA 1 had a major drawback that caused it to receive a lot of 
criticism from the community (including me): There was no way to specify custom 
type converters, so if you had some kind of special type (like a 
StackTraceElement, or a Marker, or a Message) that you wanted to support you 
had to use a provider-proprietary API to do it, or convert the value manually 
within the getter and setter. Many (again, including me) were outraged when JPA 
2.0 came out and it STILL did not have support for custom types.

So, when I created the JPA appender I created an abstract class implementing 
LogEvent called LogEventWrapperEntity. This class provides no-op setters to 
complement all of the getters defined in the interface (because JPA requires 
setters, but we don't need them because log events will be write-only). 
However, the end-user MUST implement ALL of the getters specified in the 
LogEvent interface, because how these values are converted will depend on which 
provider they use. I'm not 100% happy with that, but it works.

Enter JPA 2.1, whose final draft was approved two weeks ago and will be 
released final literally any day now, and finally there is a way to specify 
custom converters without depending on provider-specific APIs 
(@javax.persistence.Convert and javax.persistence.AttributeConverter). Using 
these, I could create AttributeConverters for StackTraceElement, Throwable, 
Message, Marker, Level, Map<String, String>, and ThreadContext.ContextStack. I 
could then create a more complete entity with all of the getters already 
defined using default column names. Then, if someone wanted to change one or 
more column names, they would only need to override the getters whose column 
names they wanted to change, and they wouldn't have to worry about type 
conversion. It would make using the JPA Appender MUCH easier.

Since JPA 2.1 is a minor version, this shouldn't so much be a problem, except 
that people using Hibernate would need to upgrade to 4.3.0 or higher ... a 
major upgrade if they're still on 3.5-3.7, but only a minor upgrade if they're 
on 4.0+ already. Hibernate 4.3.0 is currently in beta but should release soon, 
almost assuredly before Log4j 2 does. I know in both of my $work environments 
we have a need for many custom converters and will be upgrading ASAP when 4.3.0 
comes out.

So, what do you think? Which of these options do you prefer?

1) A harder-to-use JPA Appender that is more forgiving about which JPA provider 
version you use, or
2) A much easier-to-use JPA Appender that requires the absolute latest JPA 
provider version?

I lean towards 2. My thoughts are that by the time Log4j 2 becomes widely used 
JPA 2.1 providers will be the norm, not brand new like they are now. My bets 
are that the few people that will be using the JPA Appender early on are likely 
already early adopters who will already be on JPA 2.1 or don't mind upgrading.

Nick

[1] https://issues.apache.org/jira/browse/LOG4J2-229

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to