Custom code generation for JPA entities from database - java

I'm here asking for a simple way to add some custom code in the JPA Entity generated by Eclipse from database.
Basically what I want to achieve is to add public String properties containing the names of the entity properties, and use them when I need to provide "property name" as String and be sure that there won't be runtime access errors.
Something like this
#Entity
#Table(name="clients")
#NamedQuery(name="ClientModel.findAll", query="SELECT c FROM ClientModel c")
public class ClientModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="id_client")
private long idClient;
public String name;
public ClienteModel() {
}
public long getIdClient() {
return this.idClient;
}
public void setIdClient(long idClient) {
this.idClient = idClient;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
//CUSTOM CODE
public static final String idClientProperty = "idClient";
public static final String nameProperty = "name";
}
So i could use property name like
ClientModel.nameProperty
and be compile-time safe of his existence and in case of names refactoring after a further entity generation.
I'm aware of the existence of Telosys Tools & co., but I hoped there could be something simplier/faster (like a custom class provided as plugin in WSDL_to_entity generation with JAXB)
Thank you.

In the end I've used Telosys Tools, even if I didn't want to add another tool to my project,
Is kinda easy to set up, just read here
https://sites.google.com/site/telosystools/getting-started/21-configure-a-project
In my specific case i've added to the template "JPA_bean_with_links" this code during getters creation
#if ( $field.getter ) public static String ${field.getter}Property() {
return "$field.name";
}
#end

Related

Adding properties to enums in JOOQ

We have been moving away from hibernate to jooq for months now. Pattern we would often do in Hibernate would be writing a custom enum like this...
public enum HBMCapacityType {
Accepting("Accepting until end of day", true),
Limited("Limited until end of day", true),
AtCapacity("At Capacity until further notice",false);
private final String description;
private final boolean userOverridable;
HBMCapacityType(String description, boolean userOverridable) {
this.description = description;
this.userOverridable = userOverridable;
}
public String getDescription() {
return this.description;
}
public boolean isUserOverridable() {
return this.userOverridable;
}
}
Then we are able to use this a column in our hibernate domain objects
#Enumerated(EnumType.STRING)
#Type(type = "pg_enum")
#Column(name = "capacity_type", nullable = false, columnDefinition = "capacity_type")
private HBMCapacityType capacityType;
This is convenient as we can call capacityType.getDescription() when rendering to to the GUI. We have this nice 1:1 mapping of enum types to a description we can use in the GUI. Sometimes we have multiple getters like this say one for description and a few booleans which characterize behaviour associated with that enum. The property isUserOverrideable would be an example of this.
Now looking at JOOQ: since this was defined as an enum in postgres JOOQ automatically generates a type like this...
/**
* This class is generated by jOOQ.
*/
#SuppressWarnings({ "all", "unchecked", "rawtypes" })
public enum CapacityType implements EnumType {
Accepting("Accepting"),
Limited("Limited"),
AtCapacity("AtCapacity");
private final String literal;
private CapacityType(String literal) {
this.literal = literal;
}
#Override
public Catalog getCatalog() {
return getSchema().getCatalog();
}
#Override
public Schema getSchema() {
return Wastecoordinator.WASTECOORDINATOR;
}
#Override
public String getName() {
return "capacity_type";
}
#Override
public String getLiteral() {
return literal;
}
/**
* Lookup a value of this EnumType by its literal
*/
public static CapacityType lookupLiteral(String literal) {
return EnumType.lookupLiteral(CapacityType.class, literal);
}
}
I guess your question is about how to add custom properties to jOOQ generated enums? There are multiple approaches:
Using a custom code section
One way to achieve the same functionality is by adding a custom code section as described here. You'll add a generateEnumClassFooter() method to your own JavaGenerator subclass, and generate the necessary code there. Unlike in your original code, you can't modify the properties of enum values, so you'll just have to switch over this, instead.
Move the logic outside of the enum
You can always just write a static utility of the form
public static boolean isUserOverridable(HBMCapacityType type) {
return switch (type) { ... };
}
It's less object oriented, but maybe, that doesn't matter all that much?
Keep 2 separate enums
You don't have to use jOOQ's enum. You can translate it to your own hand-written enum and attach an EnumConverter to your generated code to map between the jOOQ enum type and yours.

Java nested POJO update based on dot annotation

I have a nested POJO structure defined something like this,
public class Employee {
private String id;
private Personal personal;
private Official official;
}
public class Personal {
private String fName;
private String lName;
private String address;
}
public class Official {
private boolean active;
private Salary salary;
}
public class Salary {
private double hourly;
private double monthly;
private double yearly;
}
I get updates from a service with dot annotaion on what value changed, for ex,
id change --> id=100
address change --> personal.address=123 Main Street
hourly salary change --> official.salary.hourly=100
This POJO structure could be 3-4 level deeps. I need to look for this incoming change value and update the corresponding value in POJO. What's the best way of doing it?
If you would like to create Java objects that allows you to edit fields. You can specify your object fields with the public/default/protected access modifiers. This will enable you to get and set fields such as personal.address or official.salary.hours
This approach is typically frowned upon as the object is no longer encapsulated and any calling methods are welcome to manipulate the object. If these fields are not encapsulated with getters and setters, your object is no longer a POJO.
public provides access from any anywhere.
default provides access from any package
protected provides access from package or subclass.
public class Employee {
public String id;
public Personal personal;
public Official official;
}
public class Personal {
public String fName;
public String lName;
public String address;
}
Here's a quick approach using reflection to set fields dynamically. It surely isn't and can't be clean. If I were you, I would use a scripting engine for that (assuming it's safe to do so).
private static void setValueAt(Object target, String path, String value)
throws Exception {
String[] fields = path.split("\\.");
if (fields.length > 1) {
setValueAt(readField(target, fields[0]),
path.substring(path.indexOf('.') + 1), value);
return;
}
Field f = target.getClass()
.getDeclaredField(path);
f.setAccessible(true);
f.set(target, parse(value, f.getType())); // cast or convert value first
}
//Example code for converting strings to primitives
private static Object parse(String value, Class<?> type) {
if (String.class.equals(type)) {
return value;
} else if (double.class.equals(type) || Double.class.equals(type)) {
return Long.parseLong(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
return Boolean.valueOf(value);
}
return value;// ?
}
private static Object readField(Object from, String field) throws Exception {
Field f = from.getClass()
.getDeclaredField(field);
f.setAccessible(true);
return f.get(from);
}
Just be aware that there's a lot to improve in this code (exception handling, null checks, etc.), although it seems to achieve what you're looking for (split your input on = to call setValueAt()):
Employee e = new Employee();
e.setOfficial(new Official());
e.setPersonal(new Personal());
e.getOfficial().setSalary(new Salary());
ObjectMapper mapper = new ObjectMapper();
setValueAt(e, "id", "123");
// {"id":"123","personal":{},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "personal.address", "123 Main Street");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "official.salary.hourly", "100");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":100.0,"monthly":0.0,"yearly":0.0}}}

Finding non-referenced class attributes in Eclipse

I wonder if there are another ways to find attributes in specific class are non-referenced by other classes (I mean, non used attributes).
My way is like that, for example I have a class like:
public class EABHeaderInformation implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4986763088497593972L;
//BargainFinder - AlternateBooking
private int multiTicketSequencdNmbr;
private String resBookDesigCode;
private LocalDateTime departureDate;
private LocalDateTime lastTicketingDate;
private List<String> text;
private String validatingCarrierCode;
public String getValidatingCarrierCode() {
return validatingCarrierCode;
}
public void setValidatingCarrierCode(String validatingCarrierCode) {
this.validatingCarrierCode = validatingCarrierCode;
}
public int getMultiTicketSequencdNmbr() {
return multiTicketSequencdNmbr;
}
public void setMultiTicketSequencdNmbr(int multiTicketSequencdNmbr) {
this.multiTicketSequencdNmbr = multiTicketSequencdNmbr;
}
public String getResBookDesigCode() {
return resBookDesigCode;
}
public void setResBookDesigCode(String resBookDesigCode) {
this.resBookDesigCode = resBookDesigCode;
}
public LocalDateTime getDepartureDate() {
return departureDate;
}
public void setDepartureDate(LocalDateTime departureDate) {
this.departureDate = departureDate;
}
public LocalDateTime getLastTicketingDate() {
return lastTicketingDate;
}
public void setLastTicketingDate(LocalDateTime lastTicketingDate) {
this.lastTicketingDate = lastTicketingDate;
}
public List<String> getText() {
return text;
}
public void setText(List<String> text) {
this.text = text;
}}
It's a simple POJO with getter and setters. I check every getter and setter with 'Open Call Hierarchy' in Eclipse, to find out if the attribute is used by others or not. But it takes a lot of time when I work on bigger classes than this.
So, is there a faster way to do this? Thanks for replies.
Eclipse can already create a warning or error for unused private members, but for public ones the Eclipse stance has always been that it's not a valuable feature. I tend to disagree, because many users have a limited scope that would be useful (specifically, all, or a subset of, the projects in the workspace). See this feature request, this one, and this one.
There are some third party options, such as UCDetector and this simple plug-in example.
See also this SO question and the answers.

Display only 1 field in Nested Object Metawidget

Using the metawidget to build some flexible UI in Java: https://sourceforge.net/projects/metawidget/
public class Cohort {
private int id;
private Project project;
private Member teamLead;
public Cohort() { }
#UiHidden
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public Project getProject() { return project; }
public void setProject(Project project) { this.project = project; }
public Member getTeamLead() { return teamLead; }
public void setTeamLead(Member teamLead) { this.teamLead = teamLead; }
}
Cohort is the class inspected. However as is desirable it recursively inspects both the Project and Member classes.
When displayed on the UI, it will display all the fields for each of the classes. However I would only like to display the "Name" field of the Project and firstName + last Name of the Member.
There are a number of ways to achieve this. I'll start with one and let me know if it's sufficient for your needs:
a) mark the fields of Project/Member that you don't want to see as UiHidden (you don't say what those fields are, but you seem to have gotten the idea because you are already hiding 'Cohort.getId'). Note you can also reuse existing annotations (like JPA annotations) for this purpose.
b) mark 'Cohort.getProject' and 'Cohort.getTeamLead' as UiLabel( "" ). This will suppress the sub-label for the sub-object, and make its fields appear as if part of the original object.

What does Eclipse consider as a "simple getter" or a "simple setter"?

I use the Eclipse debugger on a regular basis and this has always bugged me about the IDE. Step filtering is such an invaluable tool, that way I'm not stepping into classes that does not have source code or I'm simply not interested in. However Eclipse isn't getting it right for most cases. In particular, there are options to "Filter simple getters" and "Filter simple setters".
I might use a getter that just simply returns the value of a member variable.
private String value;
public String getValue()
{
return value;
}
Or perhaps a getter that lazily instantiates an expensive object.
private IObjectFactory instance;
public IObjectFactory getInstance()
{
if (instance == null)
instance = ObjectFactory.createFactory();
return instance;
}
I might use a setter that just sets the value of a member variable.
private String value;
public void setValue(String value)
{
this.value = value;
}
I might want to support fluent syntax.
private String value;
public ObjectFactory setValue(String value)
{
this.value = value;
return this;
}
Or perhaps do some validation or event triggering.
private String user;
public void setUser(String user)
{
if (StringUtils.isBlank(user))
throw ExceptionHelper.argumentNull("user");
this.user = user;
}
private String title;
public void setTitle(String title)
{
if (!StringUtils.equals(this.title, title))
{
this.title= title;
onPropertyChanged("title", title);
}
}
And for every single one of these uses, stepping into code using eclipse steps into these methods...
What does Eclipse consider as a "simple getter" or a "simple setter"?
The filters are definitely enabled:
In case it matters, I'm using Eclipse Kepler build 20130614-0229. I'm using JRE6 to run Eclipse and a Tomcat 7 server hosting a Java 1.4 web app. Although we ultimately target 1.4, it is compiled locally using JDK6 so I don't see that as being a problem. I do have JRebel installed and in use, perhaps the classloader is interfering with the algorithms which determine what is considered "simple"? Combined with the "Step through filters" option enabled, it's stepping through my code perhaps. I'll experiment further after thinking about this.
Ok I think I tracked it down.
Under normal circumstances, a plain getter and plain setter (examples 1 and 3 in the question) will be stepped over if these filters are enabled. If a special class loader such as JRebel which modifies methods to hook into them is installed and in use, it seems to interfere with Eclipse's algorithms which determine if a method is a "simple getter" or "simple setter".
So a getter that might look like this in code:
public String getValue()
{
return this.value;
}
Might be altered to look something like this from the JVM's perspective:
public String getValue()
{
Proxy proxy = getProxy(this);
return (String)proxy.invoke("getValue", new Object[] { });
// this is all just an example,
// it's defintely way more complicated than this
}
This altered code confuses Eclipse into thinking "that's not a simple getter so step into it". It does but the actual source code is my actual simple getter which then confuses me thinking "Why did Eclipse step into this simple getter?"
I ran a very contrived test to try to get the step filtering to work.
import org.apache.commons.lang.StringUtils;
public class Program
{
public static void main(String[] args)
{
User bob = new User("0001", "Bob");
String id = bob.getId(); //stepped over
String name = bob.getName(); //stepped over
IHome home = bob.getHome(); //stepped into
bob.setId("foo"); //stepped into
bob.setName("Bobby"); //stepped over
String asString = bob.setNameFluent("Bobbo").toString(); //stepped into
IHome newHome = Neighborhood.getHome("moo");
bob.setHome(newHome); //stepped into
return;
}
static class User
{
private String id;
private String name;
private IHome home;
public User() { this("0001", null); }
public User(String id, String name) { this.id = id; this.name = name; }
public String getId() // simple
{
return id;
}
public String getName() // simple
{
return name;
}
public IHome getHome() // not simple
{
if (home == null)
home = Neighborhood.getHome(id);
return home;
}
public void setId(String id) // not simple
{
if (StringUtils.isBlank(id))
throw ExceptionHelper.argumentBlank("id");
this.id = id;
}
public void setName(String name) // simple
{
this.name = name;
}
public User setNameFluent(String name) // not simple
{
this.name = name;
return this;
}
public void setHome(IHome home) // not simple
{
if (home != null)
{
this.home = home;
onHomeChanged();
}
}
protected void onHomeChanged()
{
this.id = home.getId();
}
public String toString()
{
return "User { name=" + getName() + ", home=" + getHome() + " }";
}
}
static interface IHome
{
String getId();
String getLocation();
}
static class Neighborhood
{
public static IHome getHome(String id)
{
return new Home(id);
}
static class Home implements IHome
{
private String id;
public Home(String id) { this.id = id; }
public String getId() { return id; }
public String getLocation() { return "Home" + id; }
public String toString() { return "Home: " + getLocation(); }
}
}
static class ExceptionHelper
{
public static IllegalArgumentException argumentBlank(String name)
{
return new IllegalArgumentException("Argument " + name + " must not be blank");
}
}
}
With the default configuration (JDK6 without JRebel), the step filtering appeared to work. Trying to step into the simple methods actually stepped over them. After enabling JRebel and stepping through the code again, it stepped into all the methods. And it doesn't matter if "Step through filters" is enabled or not.
tldr;
By using JRebel, the magic that it does confused Eclipse making simple getters and simple setters look more complicated than they originally are. Disabling JRebel will cause the filters to work as intended.
Here is a page on Eclipse's website, which describes the two options in a little more detail
Filter simple getters:
This option controls if simple Java bean-style getters should always be filtered or not while stepping
Filter simple setters:
This option controls if simple Java bean-style setters should always be filtered or not while stepping
From the sounds of it, examples 1 and 3 that you give do appear to be what they mean here. Not sure why you're seeing the behavior that you are though.
EDIT: Looks like the original poster found the issue; something about JRebel overcomplicating the methods.

Categories

Resources