9

I am using a few Java classes like javax.Mail.Session and MessageDigest for a tool I am building.

I noticed that it was difficult assigning them properties because they were using String constants for that.

For example, for a Session object, you have to assign String key value pairs in a Property instance which is then used to create a Session. So if you want your session to log debugging messages, assign "smtp.mail.debug", "true" in the Property instance. Similarly, if you want your MessageDigest to use SHA, create the MessageDigest instance as MessageDigest.getInstance("SHA")

I am yet to figure out what to do and where to get the information if say I wanted to implement MessageDigest using MD5 / RC4 etc, or add another property to my Session object.

Wouldn't it be really better if public enums were exposed by these respective classes to assign properties ?

Would save programmers lot of searching time at least.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Rajan Prasad
  • 1,582
  • 1
  • 16
  • 33
  • _"Wouldn't it be really better if public enums were exposed by these respective classes to assign properties?"_ No! – Unihedron Aug 03 '14 at 23:59
  • 1
    totally agree with @Raymond. I think it only uses String as constants because of [1] backward compatibility with std libraries developed before the existence of Enum [2] lack of enum usage enforcement and [3] the only reason where using strings were acceptable, if these parameters can't be discovered on compile time. And it's even worse when you start using numeric AWT constants masked with |. – Leo Aug 04 '14 at 00:00
  • 4
    @Unihedron : Not asking for opinions unless you are going to back it up with reasoning. – Rajan Prasad Aug 04 '14 at 00:05
  • 1
    There are three reasons: backwards compatibility, backwards compatibility, and backwards compatibility. – user207421 Aug 04 '14 at 00:10

3 Answers3

11

I can see 2 main reasons:

Backward compatibility

The two examples you give were already part of the API before enums got introduced in Java 1.5. There's many more cases like that out there.

Extensibility

Take a look at for example MessageDigest. The javadoc specifies:

Every implementation of the Java platform is required to support the following standard MessageDigest algorithms:

• MD5
• SHA-1
• SHA-256

This lets other java.security.Provider libraries provide MessageDigest implementations for other algorithms than the ones minimally required by the API. Listing only the default ones in a restrictive enum on the API level would limit extensibility.

The same goes for allowing other javax.mail.Provider implementations to support additional/custom properties in the case of mail session properties.

Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
  • 10
    Neither of these reasons are *satisfactory*. The same way `String.getBytes("UTF-8")` can accept `String.getBytes(StandardCharsets.UTF_8)`, and you don't need to handle a possible `UnsupportedEncodingException`, similar mapping could (should!) be provided for `MessageDigest.getInstance("MD5")`. Having to do runtime checking of things that are known at compile-time is always wrong. Good libraries would help you avoid this. – swalog Jan 08 '16 at 09:00
  • 2
    @swalog Could or should additional mappings with corresponding methods be provided? Sure, but for the reasons outlined above, that will not invalidate the need for the string-based methods. – Robby Cornelissen Jan 08 '16 at 09:27
  • 5
    Agreed. I should have been clear that the reasons you provided satisfies the question. My criticism is towards the api. I wanted to point out that there there is no reason for not having constants to avoid runtime string look-up for implementations that are required by the api. We could have have that *and* backwards compatibility *and* extensibility. – swalog Jan 08 '16 at 09:35
  • 2
    @swalog `StandardCharsets.UTF_8` contains the actual `Charset` implementation, so it can not fail in finding it, whereas a `MessageDigest.getInstance(HypotheticalEnumType)` still would have to go through the same code path as the string based based method to find a provider and only differ in not being allowed to throw a checked exception on failure. – Holger Mar 16 '22 at 13:43
2

This is likely due to the major focus of Java to provide backwards compatiablity to previous versions.

enum was introduced in Java 1.5, hence any API which was written against 1.4 or earlier will not provide support for this feature. This is very common amongst many of the APIs in the JDK

You also need to remember, enum is not extendable, meaning that if your wanted to introduce a new algorithm in the message digest, for example, you would be stuck...there'd be no way you could do it.

The same goes with the mail API, the mail API is provides support for distinctively different concepts, not all of them will have the same series of properties and would be impossible to devise a single enum capable of supporting ALL the various properties between different implementations that exist now or in the future, enum is just simply to inflexible for this job.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I have read about that. But they could have extended their API to allow using enums to assign properties, right ? – Rajan Prasad Aug 04 '14 at 00:04
  • 2
    @Raymond232 That's not the point of those APIs though. Those APIs are designed to provide a common frontage through which you can interact with, in some cases, `interface`s. Those `interface`s would still be limited to been able to provide access to what they know, not what might come in the future...`enum`, in this context is to restrictive... – MadProgrammer Aug 04 '14 at 00:05
2

It will be to simple to think that reason is only backward compatibility.

For JavaMail because it has too many different settings related to different connectors and you only need some part of them to setup connection with one of supported protocols. Each connector is implemented in separate class and as I think, there is no reason to let for example, POP3 connector to know settings for IMAP connector.

For MessageDigest the reason is to support non-standard encryption algorithms, which is not packed with JDK but provided by 3rd party JCE adapters. For example how it will look for GOST algorithm provided by CryptoPro JCE:

  MessageDigest digest = MessageDigest.getInstance("GOST3411"); 
Alex Chernyshev
  • 1,719
  • 9
  • 11
  • I agree with both your points, but I was looking for a more generic answer (in terms of general use of String constants). Anyways, thanks. – Rajan Prasad Aug 04 '14 at 00:50