I'm working on a configuration system. I'd like to be able to load config values from a JSON file and have them "automagically" convert to the Java type I need. I'm using Jackson for the JSON parsing. For primitive types like floats and strings, it's no big deal, but I'm running into a snag with enums.
Let's say I have the following enum:
public enum SystemMode
{
#JsonProperty("Mode1")
MODE1("Mode1"),
#JsonProperty("Mode2")
MODE2("Mode2"),
#JsonProperty("Mode3")
MODE3("Mode3");
private final String name;
private SystemMode(String name)
{
this.name = name;
}
#Override
#JsonValue
public String toString()
{
return this.name;
}
}
Now, let's say I want to represent a list of values of this enum for a given config variable using the following JSON representation:
{
"Project" : "TEST",
"System" : {
"ValidModes" : ["Mode1", "Mode2"]
}
}
And I'd like to be able to do something like the following:
ArrayList<SystemMode> validModes = (ArrayList<SystemMode>) configurator.getConfigValue("/System/ValidModes");
For reference, my configurator class's getConfigValue method is essentially a thin wrapper over the Jackson JSON parsing:
public Object getConfigValue(String JSON_String)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(JSON_String);
return objectMapper.convertValue(node, Object.class);
}
(The real method has some exception checking that has been omitted for clarity).
Now, when I call the above, Jackson correctly deduces that I want an ArrayList and fills it. However, instead of getting an ArrayList of SystemMode enums, I get an ArrayList of Strings and immediately throw an exception when I attempt to use the list. I have tried several different ways of representing the data to no avail. It seems no matter what I try, Jackson wants to return a list of strings instead of a list of enums.
So my question is this:
How can I make Jackson (version 2.9.4) JSON properly deserialize a list of enum values in a way that is compatible with my single "Object getConfigValue()" method?
The following will provide the correct binding for your enum.
public List<SystemMode> getConfigValue(String path)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
return objectMapper.convertValue(node, new TypeReference<List<SystemMode>>(){});
}
The second option is to convert the list of String yourself, for example:
List<SystemMode> result = jsonResult.stream().map(SystemMode::valueOf).collect(Collectors.toList());
Third option:
public <T>List<T> getConfigValue(String path, Class<T> type)
{
JsonNode node = JsonNodeFactory.instance.objectNode().at(path);
CollectionType toType =
objectMapper.getTypeFactory().constructCollectionType(List.class, type);
return objectMapper.convertValue(node, toType);
}
I'm using Jackson 2.7.0. and latest Jersey for JSON on REST API that handles DB communication with Hibernate 5+.
I don't know how to verify incoming JSON if there are any missing properties in it. It is impossible to perform checking on primitive type if they are null. But also i would like to use primitive types because of performance hit.
What is best practice to handle such problem?
When I receive JSON like below, everything is ok:
{"vehicle":{"id":1},"distance":1000,"quantity":2000}
But when i receive JSON like:
{"vehicle":{"id":1},"quantity":2000}
then distance is set to default value 0.
My entity look like
public class Consumption{
private int id;
private double quantity;
private double distance;
#JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public Consumption(
#JsonProperty(value = "quantity", required = true)double quantity,
#JsonProperty(value = "distance", required = true)double distance,
#JsonProperty(value = "vehicle", required = false)Vehicle vehicle) {...
And REST method:
#POST
#Path("/setConsumption/")
public Response setConsumption(#Valid Consumption consum){...
Tried solution #1
I have already tried, to set all values to default value of -1 and then check if it is less then 0, but problem remains with boolean values, where i can not set it to the "neutral" value.
How do you usually handle such problem with missing property in JSON?
Tried solution #2
As you can see i have used #JsonProperty(value = "quantity", required = true) in constructor. This is new feature for Jackson 2.7.0.+, that handles this type of problem. But i get this exception:
Missing required creator property 'distance' (index 1) at
[Source:org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#1b72cb6; line: 1, column: 181]
This exception is returned to user BEFORE JSON reaches my code. So i can not catch it as exception. I have custom responses with httpCode and errorMessage to inform user about them. Problem is that i don't know how to catch this exception and return it to user in my custom form with my text.
Searching for solution
I have either to catch exception of new Jackson feature or try to validate JSON. But i would not like to use class Integer instead of primitive data type int, because of performance.
If it is possible not to write custom JSON deserializer for all 60+ classes i have in project.
If any other solution then Jackson or Jersey supports this types of handling of missing properties, feel free to comment.
TDLR - how to check if variable of primitive data type (int, double, boolean,...) was in incoming JSON or not, without manually writting deserializers for each of 60+ classes in project. Java does not allow to check those types with null.
Suggestion #1
Trying to register an ExceptionMapper for JsonMappingException and see if it overrides the one already registered by Jersey.
My code (still getting default "Missing property ..." exception - problem not solved):
#Provider
public class JacksonNoPropertyMapper implements ExceptionMapper<JsonMappingException> {
#Override
public Response toResponse(JsonMappingException e) {
return Response.status(999).entity("OVERRIDE TEST").type(MediaType.APPLICATION_JSON).build();
}
}
The easiest way for you to approach this would be to use the Object counter parts on fields that are optional, it shouldn't affect you too much performance wise, and would allow you to null check the fields.
public class Consumption {
private int id;
private double quantity;
private Double distance;
public boolean isDistanceSet() {
return distance != null;
}
I have a POJO that is similar to:
public class MyGsonPojo {
#Expose
#SerializedName("value1")
private String valueOne;
#Expose
#SerializedName("value2")
private boolean valueTwo;
#Expose
#SerializedName("value3")
private int valueThree;
// Getters and other stuff here
}
The issue is that this object has to be serialized into a json body for a call
to the server. Some fields are optional for the request and if I even send it with default and null values, the API responds differently (Unfortunately changing the api is not an option).
So basically I need to exclude fields from serialization if any of them is set to a default value. For example if the field valueOne is null the resulting json should be:
{
"value2" : true,
"value3" : 2
}
Any idea how to make this a painless effort? I wouldn't want to build the json body manually.
Any help would be great. Thank you in advice.
Steps to follow:
Convert the JSON String into Map<String,Object> using Gson#fromJson()
Iterate the map and remove the entry from the map which are null
Form the JSON String back from the final map using Gson#toJson().
I have already posted the sample code in the same context here:
Remove empty collections from a JSON with Gson
Option 1) Use a TypeAdapter, see accepted answer here:
Option 2) If using Jackson instead of gson is a possibility, you can annotate/serialize on getters instead of on fields, and put your logic for returning
whatever you need for "default values" in your getters.
//won't get serialized because it's private
private String valueOne;
...
#JsonSerialize
String getValueOne(){
if (valueOne == null) return "true"
else...
}
You could also use a single #JsonInclude(Include.NON_NULL) or #JsonInclude(Include.NON_EMPTY) annotation at the top of your class to prevent any null or empty fields from being serialized.
Simple question/problem for anybody familiar with building APIs... I have many objects that I prefer to represent as a string rather than a Json object, for simplicity purposes.
For example, I have a date range which I could (and used to) place into an object (with start end end date members), but considering we can have multiple of these ranges, I could instead have this...
['20130210-20130315','20130520-20130524']
Which IMO looks a lot simpler and cleaner than
[
{
"start":"2013-02-10",
"end":"2013-03-15"
},
{
"start":"2013-05-20",
"end":"2013-05-24"
}
]
And this holds for various other objects which are in the main Json object for the service.
My dilemma of just treating them as Strings is that then I lose the ability to mark them with interfaces, which are used all throughout the code. (For instance, this Json in particular might be marked with a "Filter" interface which many methods take in.)
That said, is there any way to satisfy both of these conditions, i.e. having a custom Json object (implementing my own interfaces, etc.) AND have Jackson parse it like a String primitive? I'm hoping this can be accomplished without much work involving custom serialization & deserialization, since I have lots of objects.
Hate duplicating posts, so in an attempt to add some value here -- this does exactly what I want with arrays --
public class MyAwesomeJson extends JacksonObject implements S {
private final String value;
public MyAwesomeJson(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
}
Then to get the array form --
public class MyAwesomeJsonArray extends JacksonObject implements A {
private final Set<MyAwesomeJson> values = Sets.newLinkedHashSet();
public MyAwesomeJsonArray(MyAwesomeJson... values) {
this.values.addAll(Arrays.asList(values));
}
#JsonValue
public Set<MyAwesomeJson> getValues() {
return values;
}
}
System.out.println(new MyAwesomeJsonArray(new MyAwesomeJson("Yellow"),
new MyAwesomeJson("Goodbye")));
["Yellow","Goodbye"]
So, I have willfully kept myself a Java n00b until recently, and my first real exposure brought about a minor shock: Java does not have C# style properties!
Ok, I can live with that. However, I can also swear that I have seen property getter/setter code in Java in one codebase, but I cannot remember where. How was that achieved? Is there a language extension for that? Is it related to NetBeans or something?
There is a "standard" pattern for getters and setters in Java, called Bean properties. Basically any method starting with get, taking no arguments and returning a value, is a property getter for a property named as the rest of the method name (with a lowercased start letter). Likewise set creates a setter of a void method with a single argument.
For example:
// Getter for "awesomeString"
public String getAwesomeString() {
return awesomeString;
}
// Setter for "awesomeString"
public void setAwesomeString( String awesomeString ) {
this.awesomeString = awesomeString;
}
Most Java IDEs will generate these methods for you if you ask them (in Eclipse it's as simple as moving the cursor to a field and hitting Ctrl-1, then selecting the option from the list).
For what it's worth, for readability you can actually use is and has in place of get for boolean-type properties too, as in:
public boolean isAwesome();
public boolean hasAwesomeStuff();
I am surprised that no one mentioned project lombok
Yes, currently there are no properties in java. There are some other missing features as well.
But luckily we have project lombok that is trying to improve the situation. It is also getting more and more popular every day.
So, if you're using lombok:
#Getter #Setter int awesomeInteger = 5;
This code is going to generate getAwesomeInteger and setAwesomeInteger as well. So it is quite similar to C# auto-implemented properties.
You can get more info about lombok getters and setters here.
You should definitely check out other features as well.
My favorites are:
val
NoArgsConstructor, RequiredArgsConstructor, AllArgsConstructor
Logs!
Lombok is well-integrated with IDEs, so it is going to show generated methods like if they existed (suggestions, class contents, go to declaration and refactoring).
The only problem with lombok is that other programmers might not know about it. You can always delombok the code but that is rather a workaround than a solution.
"Java Property Support" was proposed for Java 7, but did not make it into the language.
See http://tech.puredanger.com/java7#property for more links and info, if interested.
The bean convention is to write code like this:
private int foo;
public int getFoo() {
return foo;
}
public void setFoo(int newFoo) {
foo = newFoo;
}
In some of the other languages on the JVM, e.g., Groovy, you get overridable properties similar to C#, e.g.,
int foo
which is accessed with a simple .foo and leverages default getFoo and setFoo implementations that you can override as necessary.
public class Animal {
#Getter #Setter private String name;
#Getter #Setter private String gender;
#Getter #Setter private String species;
}
This is something like C# properties. It's http://projectlombok.org/
You may not need for "get" and "set" prefixes, to make it look more like properties, you may do it like this:
public class Person {
private String firstName = "";
private Integer age = 0;
public String firstName() { return firstName; } // getter
public void firstName(String val) { firstName = val; } // setter
public Integer age() { return age; } // getter
public void age(Integer val) { age = val; } //setter
public static void main(String[] args) {
Person p = new Person();
//set
p.firstName("Lemuel");
p.age(40);
//get
System.out.println(String.format("I'm %s, %d yearsold",
p.firstName(),
p.age());
}
}
Most IDEs for Java will automatically generate getter and setter code for you if you want them to. There are a number of different conventions, and an IDE like Eclipse will allow you to choose which one you want to use, and even let you define your own.
Eclipse even includes automated refactoring that will allow you to wrap a property up in a getter and setter and it will modify all the code that accesses the property directly, to make it use the getter and/or setter.
Of course, Eclipse can only modify code that it knows about - any external dependencies you have could be broken by such a refactoring.
My Java experience is not that high either, so anyone feel free to correct me. But AFAIK, the general convention is to write two methods like so:
public string getMyString() {
// return it here
}
public void setMyString(string myString) {
// set it here
}
From Jeffrey Richter's book CLR via C#: (I think these might be the reasons why properties are still not added in JAVA)
A property method may throw an exception; field access never throws an exception.
A property cannot be passed as an out or ref parameter to a method; a field can.
A property method can take a long time to execute; field access always completes
immediately. A common reason to use properties is to perform thread synchronization,
which can stop the thread forever, and therefore, a property should not be
used if thread synchronization is required. In that situation, a method is preferred.
Also, if your class can be accessed remotely (for example, your class is derived from
System.MarshalByRefObject), calling the property method will be very slow, and
therefore, a method is preferred to a property. In my opinion, classes derived from
MarshalByRefObject should never use properties.
If called multiple times in a row, a property method may return a different value each
time; a field returns the same value each time. The System.DateTime class has a readonly
Now property that returns the current date and time. Each time you query this
property, it will return a different value. This is a mistake, and Microsoft wishes that
they could fix the class by making Now a method instead of a property. Environment’s
TickCount property is another example of this mistake.
A property method may cause observable side effects; field access never does. In other
words, a user of a type should be able to set various properties defined by a type in
any order he or she chooses without noticing any different behavior in the type.
A property method may require additional memory or return a reference to something
that is not actually part of the object’s state, so modifying the returned object has no
effect on the original object; querying a field always returns a reference to an object
that is guaranteed to be part of the original object’s state. Working with a property
that returns a copy can be very confusing to developers, and this characteristic is frequently
not documented.
If you're using eclipse then it has the capabilities to auto generate the getter and setter method for the internal attributes, it can be a usefull and timesaving tool.
I'm just releasing Java 5/6 annotations and an annotation processor to help this.
Check out http://code.google.com/p/javadude/wiki/Annotations
The documentation is a bit light right now, but the quickref should get the idea across.
Basically it generates a superclass with the getters/setters (and many other code generation options).
A sample class might look like
#Bean(properties = {
#Property(name="name", bound=true),
#Property(name="age,type=int.class)
})
public class Person extends PersonGen {
}
There are many more samples available, and there are no runtime dependencies in the generated code.
Send me an email if you try it out and find it useful!
-- Scott
There is no property keyword in java (like you could find it in C#) the nearest way to have 1 word getter/setter is to do like in C++:
public class MyClass
{
private int aMyAttribute;
public MyClass()
{
this.aMyAttribute = 0;
}
public void mMyAttribute(int pMyAttributeParameter)
{
this.aMyAttribute = pMyAttributeParameter;
}
public int mMyAttribute()
{
return this.aMyAttribute;
}
}
//usage :
int vIndex = 1;
MyClass vClass = new MyClass();
vClass.mMyAttribute(vIndex);
vIndex = 0;
vIndex = vClass.mMyAttribute();
// vIndex == 1
As previously mentioned for eclipse, integrated development environment (IDE) often can create accessor methods automatically.
You can also do it using NetBeans.
To create accessor methods for your class, open a class file, then Right-click anywhere in the source code editor and choose the menu command Refactor, Encapsulate Fields.
A dialog opens. Click Select All, then click Refactor.
Voilà,
Good luck,
For me the problem is two fold:
All these extra methods {get*/set*} cluttering up the class code.
NOT being able to treat them like properties:
public class Test {
private String _testField;
public String testProperty {
get {
return _testField;
}
set {
_testField = value;
}
}
}
public class TestUser {
private Test test;
public TestUser() {
test = new Test();
test.testProperty = "Just something to store";
System.out.printLn(test.testProperty);
}
}
This is the sort of easy assignment I would like to get back to using. NOT having to use 'method' calling syntax. Can anyone provide some answers as to what happened to Java?
I think that the issue is also about the unnecessary clutter in the code, and not the 'difficulty' of creating the setters/getters. I consider them as ugly-code. I like what C# has. I don't understand the resistance to adding that capability to Java.
My current solution is to use 'public' members when protection is not required:
public class IntReturn {
public int val;
}
public class StringReturn {
public String val;
}
These would be used to return value from say a Lambda:
StringReturn sRtn = new StringReturn()
if(add(2, 3, sRtn)){
System.out.println("Value greater than zero");
}
public boolean add(final int a, final int b, final StringReturn sRtn){
int rtn = a + b;
sRtn.val = "" + rtn;
return rtn > 0; // Just something to use the return for.
}
I also really don't like using a method call to set or get an internal value from a class.
If your information is being transferred as 'immutable', then the new Java record could be a solution. However, it still uses the setter/getter methodology, just without the set/get prefixes.