1    Introduction

1.1    Overview

std.lib.enum is part of the standard foundation library set. This page collects the public API reference for the namespace.

2    Walkthrough

2.1    Inspecting Java enums

std.lib.enum makes it easy to work with Java enums from Clojure. Check if a class is an enum, list its values, and convert between strings, keywords, and enum instances.

check and list enum values

^{:refer std.lib.enum/enum? :added "3.0"}
(enum? java.lang.annotation.ElementType)
=> true

^{:refer std.lib.enum/enum-values :added "3.0"}
(->> (enum-values ElementType)
     (map str)
     (set))
=> (contains #{"TYPE" "FIELD" "METHOD" "PARAMETER" "CONSTRUCTOR"})

convert to and from enum instances

^{:refer std.lib.enum/create-enum :added "3.0"}
(create-enum "TYPE" ElementType)
=> ElementType/TYPE

^{:refer std.lib.enum/to-enum :added "3.0"}
(to-enum :field ElementType)
=> ElementType/FIELD

^{:refer std.lib.enum/enum-map :added "3.0"}
(enum-map ElementType)
=> (satisfies [:annotation-type
               :constructor
               :field
               :local-variable
               :method
               :module
               :package
               :parameter
               :record-component
               :type
               :type-parameter
               :type-use]
              (comp vec sort keys))

3    API



create-enum ^

[s type]
Added 3.0

creates an enum value from a string

v 3.0
(defn create-enum
  ([s type]
   (loop [[e :as values] (enum-values type)]
     (cond (empty? values)
           (throw (ex-info "Cannot create enum" {:type type
                                                 :value s}))
           (= (str e) s) e

           :else
           (recur (rest values))))))
link
(create-enum "TYPE" ElementType) => ElementType/TYPE

enum-map ^

[type]
Added 3.0

cached map of enum values

v 3.0
(definvoke enum-map
  [:memoize]
  ([type]
   (coll/map-juxt [(comp keyword case/spear-case coerce/to-string)
                   identity]
                  (enum-values type))))
link
(enum-map ElementType) => (satisfies [:annotation-type :constructor :field :local-variable :method :module :package :parameter :record-component :type :type-parameter :type-use] (comp vec sort keys))

enum-map-form ^

[type]
Added 3.0

creates the form for the enum

v 3.0
(defn enum-map-form
  ([^Class type]
   (coll/map-juxt [(comp keyword case/spear-case str)
                   #(symbol (.getName type) (str %))]
                  (enum-values type))))
link
(enum-map-form ElementType) => '{:package java.lang.annotation.ElementType/PACKAGE, :type-use java.lang.annotation.ElementType/TYPE_USE, :method java.lang.annotation.ElementType/METHOD, :field java.lang.annotation.ElementType/FIELD, :type java.lang.annotation.ElementType/TYPE, :module java.lang.annotation.ElementType/MODULE, :record-component java.lang.annotation.ElementType/RECORD_COMPONENT :type-parameter java.lang.annotation.ElementType/TYPE_PARAMETER, :constructor java.lang.annotation.ElementType/CONSTRUCTOR, :local-variable java.lang.annotation.ElementType/LOCAL_VARIABLE, :annotation-type java.lang.annotation.ElementType/ANNOTATION_TYPE, :parameter java.lang.annotation.ElementType/PARAMETER}

enum-map> ^

[type]
Added 3.0

a macro for getting elements of the enum

v 3.0
(defmacro enum-map>
  ([type]
   (enum-map-form (resolve type))))
link
(enum-map> ElementType) => {:package ElementType/PACKAGE, :type-use ElementType/TYPE_USE, :method ElementType/METHOD, :field ElementType/FIELD, :type ElementType/TYPE, :module ElementType/MODULE, :record-component ElementType/RECORD_COMPONENT :type-parameter ElementType/TYPE_PARAMETER, :constructor ElementType/CONSTRUCTOR, :local-variable ElementType/LOCAL_VARIABLE, :annotation-type ElementType/ANNOTATION_TYPE, :parameter ElementType/PARAMETER}

enum-values ^

[type]
Added 3.0

returns all values of an enum type

v 3.0
(defn enum-values
  ([^Class type]
   (let [method (.getMethod type "values" (make-array Class 0))
         values (.invoke method nil (object-array []))]
     (seq values))))
link
(->> (enum-values ElementType) (map str)) => (contains ["TYPE" "FIELD" "METHOD" "PARAMETER" "CONSTRUCTOR"] :in-any-order :gaps-ok)

enum? ^

[type]
Added 3.0

check to see if class is an enum type

v 3.0
(defn enum?
  ([type]
   (if (-> (cls/ancestor:list type)
           (set)
           (get java.lang.Enum))
     true false)))
link
(enum? java.lang.annotation.ElementType) => true (enum? String) => false

to-enum ^

[s type]
Added 3.0

gets an enum value given a symbol

v 3.0
(defn to-enum
  ([s type]
   (let [key ((comp keyword case/spear-case coerce/to-string) s)]
     (or (get (enum-map type) key)
         (throw (ex-info "Cannot find the enum value."
                         {:input s
                          :key key
                          :type type
                          :options (sort (keys (enum-map type)))}))))))
link
(to-enum "TYPE" ElementType) => ElementType/TYPE (to-enum :field ElementType) => ElementType/FIELD

4    std.lib.enum: A Comprehensive Summary

The std.lib.enum namespace provides a set of utility functions for working with Java enum types in Clojure. It simplifies common tasks such as checking if a class is an enum, retrieving its values, converting between string/keyword representations and enum instances, and generating maps of enum values. This module is particularly useful for enhancing interoperability with Java APIs that extensively use enums.

Key Features and Concepts:

  1. Enum Type Checking:n enum? [type]: A predicate that returns true if the given type (a java.lang.Class) is a Java enum, and false otherwise. It checks if the type's ancestor list includes java.lang.Enum.nn2. Enum Value Retrieval:n enum-values [type]: Returns a sequence of all enum instances for a given enum type. It achieves this by reflectively invoking the static values() method available on all Java enum classes.nn3. Enum Instance Creation:n create-enum [s type]: Creates an enum instance of the specified type from its string representation s. It iterates through the enum's values to find a match, throwing an exception if no match is found.nn4. Enum Mapping and Conversion:n enum-map [type]: A memoized function that returns a map where keys are kebab-cased keywords (derived from the enum's string name) and values are the corresponding enum instances. This provides a convenient way to look up enum values using Clojure keywords.n enum-map-form [type]: A helper function that generates the Clojure form for enum-map, useful for macro expansion.n enum-map> [type]: A macro that expands to the result of enum-map-form, allowing enum maps to be generated at compile time.n * to-enum [s type]: Converts a string or keyword s into an enum instance of the specified type. It uses enum-map for efficient lookup, handling both string and keyword inputs by converting them to kebab-cased keywords.

Usage and Importance:

The std.lib.enum module is crucial for applications within the foundation-base project that need to interact with Java APIs that utilize enums. It provides:

  • Simplified Interoperability: Bridges the gap between Clojure's dynamic nature and Java's static enum types, making it easier to work with Java enums in a Clojure-idiomatic way.n Type Safety and Validation: Functions like create-enum and to-enum ensure that attempts to create enum instances from invalid strings or keywords are caught, preventing runtime errors.n Readability and Convenience: The enum-map and enum-map> functions provide a convenient keyword-based lookup mechanism, improving code readability and reducing boilerplate when dealing with enum values.n* Performance: The use of memoization in enum-map ensures that the mapping of enum values is computed only once, improving performance for repeated lookups.

By offering these specialized utilities for Java enums, std.lib.enum enhances the foundation-base project's ability to seamlessly integrate with and leverage the broader Java ecosystem.