I have a current state where an enum
MyType represent Type table with columns as:
ID
Name
And it's used to identify type using ID parameter with byId
method:
public enum MyType {
FIRST_TYPE("First Type", 10),
SECOND_TYPE("Second Type", 20);
public static class Holder {
static Map<Integer, MyType > idMap = new HashMap<>();
private Holder() { }
}
private MyType(String name, Integer id) {
this.name = name;
this.id = id;
Holder.idMap.put(id, this);
}
public String getName() {
return name;
}
public static MyType byId(Integer id) {
return Holder.idMap.get(id);
}
My new requirement is to support also values exists in Type table, I found answers for dynamic enum, but accept answer is not to do it
No. Enums are always fixed at compile-time. The only way you could do this would be to dyamically generate the relevant bytecode.
What will be a better solution for finding also values (mainly IDs) from database (for example ID 30)
select ID from TYPE
Can I extends existing state instead of change it? can I add extra IDS from database using method?
EDIT
Even if I update as @StefanFischer suggested an interface which populate map with enum class and new database class, I still expect in code an enum return by byId
method,
public interface MyType {
public static class Holder {
static Map<Integer, MyType> idMap = new HashMap<>();
private Holder() { }
}
public default void add(MyType myType, Integer id) {
Holder.idMap.put(id, myType);
}
public static MyType byId(Integer id) {
return Holder.idMap.get(id);
}
}
If I understand it correctly the requirements are:
Type
from the databaseSo a enum can not be extended dynamically, but we could switch to a class.
So staying close to your code one could write something like:
import java.util.HashMap;
import java.util.Map;
public class MyType {
static Map<Integer, MyType> idMap = new HashMap<>();
static {
idMap.put(10, new MyType("First Type"));
idMap.put(20, new MyType("Second Type"));
}
private final String name;
private MyType(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static MyType byId(Integer id) {
return idMap.get(id);
}
public static void addType(String name, Integer id) {
MyType lookup = byId(id);
if(lookup != null) {
if(!lookup.getName().equals(name)) {
System.out.println("conflicting redefinition for id " + id + ": '" + name + "' vs '" + lookup.name + "'");
//handle...
}
}
idMap.put(id, new MyType(name));
}
}
Test Data
Let's assume we have the following in the database:
stephan=# select * from Type;
id | name
----+-------------
30 | Third Type
10 | First Type
20 | Second Type
(3 rows)
So in the database we have the predefined types with id=10 and id=20 but also a type with id=30 that is not known per default to the application. But we can populate the types from the database.
Test Case
public static void main(String[] args) {
try {
Connection connection = createConnection();
try (connection) {
populateTypes(connection);
}
MyType type;
type = MyType.byId(10);
System.out.println(type.getName());
type = MyType.byId(20);
System.out.println(type.getName());
type = MyType.byId(30);
System.out.println(type.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
JDBC Example
It doesn't matter what actual database technology is used to retrieve the values. Here an example for JDBC:
private static void populateTypes(Connection connection)
throws SQLException {
String sql = "SELECT * FROM type";
try (Statement st = connection.createStatement()) {
try (ResultSet rs = st.executeQuery(sql)) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
MyType.addType(name, id);
}
}
}
}
Demo Output
First Type
Second Type
Third Type
Is that what you are looking for?