Is there any way to use JAXB annotations on default methods inherited from Java 8 interfaces?
I created a sample maven project at https://github.com/ruckc/jaxb-java8-javafx highlighting the shims required for what I would like to do.
In dealing with JavaFX properties, i've found that I can use the default methods on interfaces to remove the annoying getters/setters from the data object.
public interface Named {
#XmlAttribute(name="name")
default String getName() {
return nameProperty().get();
}
default void setName(String name) {
nameProperty().set(name);
}
StringProperty nameProperty();
}
This removes alot of redundant code inside the implementations. My issue is that now, when trying to marshall the objects using JAXB, I still have to implement the methods (annotated with #Shim) in the implementations, so that the annotations are picked up.
#XmlRootElement(name="business")
public class Business implements Named {
private final StringProperty nameProperty = new SimpleStringProperty();
#Shim
#Override
public void setName(String name) {
Named.super.setName(name);
}
#Shim
#XmlAttribute(name="name")
#Override
public String getName() {
return Named.super.getName();
}
#Override
public StringProperty nameProperty() {
return nameProperty;
}
}
In short, if I remove the #Shim the printed out xml from the main method doesn't contain the name attribute, and the printed out name attribute from the unmarshalled string is null. I'd really like avoiding spurious/duplicate code.
Related
Sorry if the title is a bit confusing, I didn't really know how to word what I wanted to ask.
Basically, I am making an api call to a database that returns data as such:
[{"profiles":{"testexample":{"addresses":[{"city":"","street1":"","street2":"apt 320"}],"addressType":"HOME","city":"","dateOfBirth":"","emailAddress1":"","emailAddress2":"","emailAddresses":[{"email":"","preferred":1,"type":"BUSINESS"},{"email":"","preferred":0,"type":"PERSONAL"}],"firstName":"","lastName":"","phoneNumber":"","phoneNumbers":[],"phoneType":"HOME","postalCode":"","preferred":1,"street1":"","street2":""}]
The code I have below works fine when the database returns a non-empty profiles {}. I have the following Java classes that looks like the following:
public class Account {
#JsonProperty("profiles")
private Profiles profiles;
#JsonProperty("profiles")
public Profiles getProfiles() {
return profiles;
}
#JsonProperty("testexample")
public void setProfiles(Profiles profiles) {
this.profiles = profiles;
}
}
public class Profiles {
#JsonProperty("testexample")
private Profile testExample;
#JsonProperty("testexample")
public Profile getTestExample() {
return testExample;
}
#JsonProperty("testexample")
public void setTestExample(Profile testExample) {
this.testExample = testExample;
}
}
public class Profile {
#JsonProperty("dateOfBirth")
private String dateOfBirth;
#JsonProperty("dateOfBirth")
public String getDateOfBirth() {
return dateOfBirth;
}
#JsonProperty("dateOfBirth")
public void setDateOfBirth(String dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
}
So what I want to do when I get the data is check whether the getProfiles() returns empty, so I don't make the calls to anything within that object.
Please note, for the sake of simplicity I omitted other parts of the classes to focus primarily on what I wanted
This is what I have so far, and it works when the profiles {} is not empty
Account response = access.lookup(id, type); //This is to grab the response from the database, which is working.
response.getProfiles(); //This is the part that works when it has a profiles {} not empty, but fails on empty.
So what happens is that I don't get an error for response.getProfiles(), but if I tried to do response.getProfiles().getDateOfBirth(), it won't work because it will give a null pointer exception since the dateOfBirth isn't there.
I want to avoid calling anything within response.getProfiles() by skipping it if it's empty.
You need some basic null checking. The most basic way is to assign a new variable and check.
Profiles profiles = account.getProfiles();
if(profiles != null) {
//dosomething with profiles.getDateOfBirth()
}
The more "modern" functional Java way would be to use the Optional class.
String dateOfBirth = Optional.ofNullable(account.getProfiles())
.map(profile -> profile.getDateOfBirth)
.orElse(null);
(A note about your example: In the Account class, you have this.
#JsonProperty("testexample")
public void setProfiles(Profiles profiles) {
this.profiles = profiles;
}
Which appears to be an incorrect #JsonProperty annotation and might be causing some problems.
That said, it is not necessary to annotate the getters and setters. The one annotation on the field is sufficient.)
I have to create POJOs so that I can generate XML using JAXB for the below XML (Just a sample because child elements may go beyond 40).
Here, important thing to note is that I cannot declare these elements as properties in POJO because I won't be knowing the elements name.
<User>
<FirstName>Mahendra</FirstName>
<MiddleName>Singh</MiddleName>
<LastName>Dhoni</LastName>
<Organization>
<Name>Electronics</Name>
<id>elc001</id>
</Organization>
<Manager>
<Name>Sourabh</Name>
<id>emp_001</id>
</Manager>
</User>
I have created POJO for above XML as:
Fields1.java : For elements having value only.
public class Fields1
{
#XmlTransient
public String fieldName1;
#XmlValue
public String value;
// getter,setter
}
Fields2.java : For elements having child elements.
public class Fields2
{
#XmlTransient
public String fieldName2;
#XmlElement(name="NAME")
public String name;
#XmlElement(name="ID")
public String id;
// getter,setter
}
User.java : Root element class
public class User
{
#XmlVariableNode("fieldName1")
public List<Fields1> fields1;
#XmlVariableNode("fieldName2")
public List<Fields2> fields2;
// getter, setter
}
Here, #XmlVariableNode is helping me to generate elements name dynamically.
1. But, it only works fine if there is only single property
2. and if, there are two properties then it just works for the first one and ignores the next.
AFAIK, multiple #XmlVariableNodes in the same class are not possible. EclipseLink's documentation states:
Since this [#XmlVariableNode] makes use of the any logic during unmarshal and MOXy only
handles one Any mapping on a class if a class makes use of the
XmlVariableNode annotation then that class can not have XmlAnyElement
annotations or any other variables that would cause AnyObject or
AnyCollection mappings to be created.
(Source: EclipseLink/DesignDocs/406697)
You might be able to solve your problem by using nested #XmlVariableNodes:
public class TopLevelField {
#XmlTransient
public String fieldName;
#XmlVariableNode("fieldName")
public List<NestedField> fields;
// ...
}
public class NestedField {
#XmlTransient
public String fieldName;
#XmlValue
public String value;
// ...
}
#XmlRootElement
public class User {
#XmlVariableNode("fieldName")
public List<TopLevelField> fields;
}
I'm playing with java standard CDI and there is one concept I cannot get my head around. In the example below the Application class "requires" the Person class which cannot be injected since it has non-zero args constructor. How should I handle this scenario with CDI?
#Default
class Person {
private String name;
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
class Application {
#Inject
public Application(Instance<Person> p)
}
There are three ways to inject objects without a no-args constructor. One is to use a producer to create the object.
#Produces
private Person producePerson() {
return new Person(name);
}
The second is to annotate one of the constructors with #Inject and make sure all of the parameters are valid injection targets.
class Person {
private String name;
#Inject
Person(String name) {
this.name=name;
}
String getName() {
return this.name;
}
}
and somewhere else:
#Produces
private String producePersonName() {
return name;
}
(Setting up multiple of these kinds of injections may require creating some qualifier annotations)
The third is to mess around with CDI container initialization with a custom extension, but that is overkill for such a relatively simple need.
I'm looking for an eclipse plugin that can generate fluent API methods in my beans.
For instance, given this bean:
public class MyBean {
private String name;
private int age;
//Setters and getters
}
Is there any eclipse plugin that generates these methods for me?
public class MyBean {
private String name;
private int age;
public MyBean withName(String name) {
setName(name);
return this;
}
public MyBean withAge(int age) {
setAge(age);
return this;
}
//Setters and getters
}
I've found a google plugin that generates Builder objects, but I prefer fluent API inside each Bean class.
While can't find anything, you can do like me.
Generate the setters, then "Find" (checking "regular expressions") for:
\tpublic void set(.+)\((.+)\) \{\R\t\tthis\.(.+) = (.+);\R\t\}
 and replace with:
\tpublic [PUT_TYPE_HERE] with$1\($2\) \{\R\t\tthis\.$3 = $4;\R\t\treturn this;\R\t\}
Probably there's a simpler expression, but this works ;)
[UPDATE] # 07-MAR-2018
I'm now using lombok which generates getters, setters and builders throught simple annotations. (#Getter, #Setter and #Builder respectively)
It can generate with methods using the #Wither annotation too, but unfortunately its an experimental feature so it should be avoided.
In playframework, it uses javassist library to let the public fields of a class can be used as property.
See the example:
public class User {
public String name;
}
User user = new User();
user.name = "Freewind"
System.out.println(user.name);
In compilation time, play enhanced the bytecode with javassist, the final code is similar to:
public class User {
private String name;
public String getName() { return this.name; };
public void setName() { this.name = name; };
}
User user = new User();
user.setName("Freewind");
System.out.println(user.getName());
You can see not only the field name has getter and setter, but also the invocations of it changed to getters and setters.
I wonder if there is any other way to do the same (use other things than javassist)?
I found Annotation Processing Tool, but I'm not sure it can do it.
Or aspectj? Or something else?
You can look at Project Lombok, which does something similar, but with annotations. With project lombok you do need to use the getters and setters in your own code.
Not without other tools.
Unlike C#, Java does not support properties.