Reputation: 145
I have a Class with @Table annotation, currently I directly set the Name value like this :
@Data
@Entity
@NoArgsConstructor
@Table(name = "US_STUDENTS" )
public class Student {
// some properties
}
I have a table in DB named MasterCountries which have a Column name - value = countryPrefix - "US_"
When the Spring boot app run, I want to take this data from the DB and use it as part of the @Table name value to make it like this :
@Data
@Entity
@NoArgsConstructor
@Table(name = countryPrefix + "STUDENTS" ) // so the end result will be "US_STUDENTS"
public class Student {
// some properties
}
I've google'd and still have not found a solution to this, the reason is because I want to make it dynamic, whenever this spring boot service need to be redeployed for other country, just need to retrieve the specific countryPrefix from the DB, so no need to change the code again for each country Deployment.
for the repository I set up an interface that extends JpaRepository as shown below :
public interface MasterCountriesRepository extends JpaRepository<CountriesSetting, Long> {
CountriesSetting findByCountryCode(String countryCode);
}
and for the CountriesSetting entity :
@Data
@Entity
@NoArgsConstructor
@Table(name = "MasterCountries" )
public class CountriesSetting {
// some properties
}
Is this possible to achieve in spring JPA ? please ignore any mistype or minor syntax problem, as this is not the real code. Thanks in advance.
Upvotes: 2
Views: 1984
Reputation: 103018
Annotations require that everything involved in their usage is a compile time constant. That's by java spec, you can't ask the compiler to forget about that restriction just for a moment.
Any expression is a 'compile time constant' if it is:
null
doesn't count!X ! Y
where X and Y are 'compile time constant', and !
is some operator, such as + or -.String
or primitive, [D] whose initializing expression is 'compile time constant' (using this same definition, recursively).Thus, Foo.x
is compile time constant given:
class Foo {
static final int x = 5 - 3 + Integer.MAX_VALUE - Bar.y;
}
class Bar {
static final int y = 10;
}
but these aren't:
static final long z = System.currentTimeMillis();
static final String y = null;
static final String a = LocalDate.of(2020, 1, 1).toString();
Note that the third seems constant (the output of that expression is set in stone and will be the same on all VMs, forever), and yet doesn't count, as it isn't explicitly named in the java lang spec.
Given that you want to retrieve this from the database, what you want is impossible - as surely your intent is that the table name is not locked in during compilation, and yet the reason why the expression you feed to an annotation param must be compile time constant is that the compiler must lock it in.
Don't use the annotations. Annotations that are queried at runtime are usually a configuration shortcut. Generally there is a more roundabout way to achieve the same goal, calling APIs which default to 'I shall just read out the annotation value'.
Annotations can also be queried at compile time - lombok does that, as do Annotation Processors (e.g. processors that produce XML-based config files during your compilation run). Trivially it should be obvious to you that your entire plan cannot possibly work then - these are fundamentally 'at compile time' concepts.
Thinking out of the box, perhaps:
Have a separate script that will run a CREATE OR REPLACE VIEW
statement that creates a view with a singular name (just Students
for example), that just mirrors a stated table (Such as US_Students
), using ON INSERT
and ON UPDATE
and ON DELETE
to also 'pass through' any attempt to insert/update/delete attempts on this view to end up affecting the US_Students
table.
To 'change' the 'country', just run that script one-off and restart the java app, and voila.
How to make views and have them work with delete/insert/update depends on your DB engine. In both MySQL and postgres, a basic view on a simple SELECT
without aggregates and joins and such 'just works'.
You're really just looking at:
CREATE OR REPLACE VIEW Students AS SELECT * FROM US_Students;
run that single statement and you're good to go.
Upvotes: 3