Jackson's ObjectMapper().writeValueAsString() ignores variables that begin with "is_" - java

If a have an anonymous class like:
val a = object {
val is_something = "some value"
val something = "other value"
}
and call
println(ObjectMapper().writeValueAsString(a))
the result would be
"{"something":"other value"}"
And it's like this for all variables that begin with "is_". Why?
Correction, it doesn't ignore it. It takes off the "is" and moves the variable to the end of the string. So here the result would be
"{"something":"other value","_something":"some value"}"
Still, why does it do that?

Jackson apparently scans the class that you pass in for getters and setters
and then use those methods for serialization and deserialization.
"Get", "Set", "is" are eliminated and what remains in those methods will be used as Json field.
Hence your "is_something" is changed into "_something" and so on.

The issue was solved by adding #JsonProperty on top of "is_something" and capitalizing it.
So the object would look like
val a = object {
#JsonProperty
val Is_something = "some value"
val something = "other value"
}
Still have no idea what caused the problem

Related

In Kotlin, how does GSON.fromJson(...) manage to mutate a read-only field of an existing object?

In Kotlin, how can an instance's read-only val field be mutated?
In the following Kotlin code, gson.fromJson(...) gets a Thing(0) from the InstanceCreator and somehow manages to mutate value from 0 to 1, then return that object. How?
import com.google.gson.GsonBuilder
import com.google.gson.InstanceCreator
class Thing(val value: Int)
fun main() {
val creator = InstanceCreator { Thing(0) }
val gson = GsonBuilder().registerTypeAdapter(Thing::class.java, creator).create()
val thing = gson.fromJson("""{"value":1}""", Thing::class.java)
println(thing.value) // 1
}
I verified that the object returned by gson.fromJson(...) is the same object provided by the InstanceCreator, so it's not creating a new instance based on the one provided by the InstanceCreator.
I also tried setting value using reflection, but didn't find a way. There was no setter available on the val field.
I also tried setting value using reflection
Well, you can do it if you use Java's reflection API, rather than Kotlin's.
Kotlin val properties translates to a private Java field with only a public getter. You can set the private field using reflection. For example:
val x = Thing(10)
val valueField = x.javaClass.getDeclaredField("value")
valueField.trySetAccessible()
valueField.setInt(x, 20)
println(x.value)
This is probably also what Gson does under the hood.

Kotlin accessing variable from other class not by name directly but by string variable

I'm trying to access a variable from another class. The usual way would be:
in Class A
var something = ClassB().element
in Class B
val element = "hi"
Is it also possible to address element not by its name directly, but when I have the name stored in a string? So I have a string that holds
var name = "element"
and want to do something like
var something = ClassB().name //(this doesn't work)
The reason I'm asking is because I have a class in which I do some pitch processing and another class in which I store all of my pitch data in float arrays (the Hz values of different musical notes for different tunings of different instruments)
In the class I do my pitchprocessing in I want to select the right float array depending on a user selection (made with a spinner), which I "translate" with a map (so for example the spinner says "Standard Tuning" and the according array would be called "guitarStandard", in my map "Standard Tuning" would be the key and "guitarStandard" the according value). To not hardcode the different cases in which I need different arrays with if statements, I simply want the name of the array stored in a string by getting the correct value of my map and adress it that way.
I feel like that should be either super simpel or I'm thinking about it the completely wrong way, can someone help out? Thanks
I would advise that you don't store a list of strings, and instead store a list of lambdas that return property values:
class Foo {
val prop1 = arrayOf(1.0, 2.0, 3.0)
val prop2 = arrayOf(4.0, 5.0, 6.0)
}
fun main() {
val props: List<(Foo) -> Array<Double>> = listOf({it.prop1}, {it.prop2})
val foo = Foo()
for (prop in props) {
println(prop(foo).toList())
}
}
But, if you wanted to search up property names from a string, you should look into reflection.
I'd suggest to refactor your ClassB by extracting those properties to separate enum class:
enum class Tunes(vararg f: Float) {
TUNE1(1.0f, 2.0f, 3.0f), TUNE2(4.0f, 5.0f, 6.0f);
val frequencies: FloatArray = f
}
That will make your mapping more straightforward and won't involve reflection:
import Tunes.*
val mapping = mapOf("Standard Tuning" to TUNE1, "Alternate Tuning" to TUNE2)
val result = mapping[userInput]?.frequencies

How to use setter for this Kotlin class property?

I have the following class coded in Kotlin:
class MyClass {
var color: String = ""
var action: String = ""
val owners = Array(1) {Owner()}
class Owner {
var userId: String = ""
var userName: String = ""
}
}
...and I'm accessing it Java:
MyClass myObject = new MyClass();
myObject.setColor("blue");
myObject.setAction("throw");
...and I'd like to be able to set the owner. I'm not sure how, though. If it were an object that was coded in Java with public members, I'd just do something like:
myObject.owners[0].userId = "001";
myObject.owners[0].userName = "Freddy"
Since the object was coded in Kotlin, I need to user a setter in Java.
How do I set the properties in the first element of an array with a setter?
For each Kotlin property foo, you can call its getter in Java as getFoo() and, if the property is mutable, the setter as setFoo(value).
See: Calling Kotlin from Java — Properties
In your case, just access the array with the getter, take its item and call the setters: myObject.getOwners()[0].setUserId("001"); and myObject.getOwners()[0].setUserName("Freddy");, or assign the Owner to a local variable:
MyClass.Owner owner = myObject.getOwners()[0];
owner.setUserId("001");
owner.setUserName("Freddy");
Use getOwners which will return owners object then set the value.
myObject.getOwners()[0].setUserId("001");
myObject.getOwners()[0].setUserName("Freddy");

How to unmarshall XML with default value as empty string using XStream?

I am trying to figure out how to unmarshall XML when a tag is missing, I can set the default value as empty string instead of NULL. Currently XStream is using null, which is not what I want.
This class has like over 40 properties, which are all String. There is a constructor with default value for each. I mean, like this:
case class MyData(id: String = "", b: String = "", ....)
(yes, I am trying to use it with Scala)
Technically I could write a custom converter that sets them as empty string, but that feels a little silly.
I tried using this
new XStream(new PureJavaReflectionProvider())
as suggested from here: https://stackoverflow.com/a/29747705/598562
It doesn't seem to work though.
any other idea?
XStreams uses a default, empty constructor and then follows it up by calling setters afterwards. So, to get this to work without a custom converter then you will need to create an explicit empty constructor which fills everything in with the defaults you expect. Here is a sample, working application:
import com.thoughtworks.xstream.XStream
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider
object Hello extends App {
val xstream = new XStream(new PureJavaReflectionProvider())
xstream.alias("MyData", classOf[MyData])
val output = xstream.fromXML("<MyData><id>This should fill in</id></MyData>")
println(output)
}
case class MyData(id: String = "", var b: String = "")
{
def this() = this("", "")
}

Java annotations

I've created simple annotation in Java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Column {
String columnName();
}
and class
public class Table {
#Column(columnName = "id")
private int colId;
#Column(columnName = "name")
private String colName;
private int noAnnotationHere;
public Table(int colId, String colName, int noAnnotationHere) {
this.colId = colId;
this.colName = colName;
this.noAnnotationHere = noAnnotationHere;
}
}
I need to iterate over all fields, that are annotated with Column and get name and value of field and annotation. But I've got problem with getting value of each field, since all of them are of different data type.
Is there anything that would return collection of fields that have certain annotation?
I managed to do it with this code, but I don't think that reflection is good way to solve it.
Table table = new Table(1, "test", 2);
for (Field field : table.getClass().getDeclaredFields()) {
Column col;
// check if field has annotation
if ((col = field.getAnnotation(Column.class)) != null) {
String log = "colname: " + col.columnName() + "\n";
log += "field name: " + field.getName() + "\n\n";
// here i don't know how to get value of field, since all get methods
// are type specific
System.out.println(log);
}
}
Do I have to wrap every field in object, which would implement method like getValue(), or is there some better way around this? Basicly all I need is string representation of each field that is annotated.
edit: yep field.get(table) works, but only for public fields, is there any way how to do this even for private fields? Or do I have to make getter and somehow invoke it?
Every object should has toString() defined. (And you can override this for each class to get a more meaningful representation).
So you where your "// here I don't know" comment is, you could have:
Object value = field.get(table);
// gets the value of this field for the instance 'table'
log += "value: " + value + "\n";
// implicitly uses toString for you
// or will put 'null' if the object is null
Reflection is exactly the way to solve it. Finding out things about types and their members at execution time is pretty much the definition of reflection! The way you've done it looks fine to me.
To find the value of the field, use field.get(table)
Reflection is exactly the way to look at annotations. They are a form of "metadata" attached to the class or method, and Java annotations were designed to be examined that way.
Reflection is one way to process the object (probably the only way if the fields are private and don't have any kind of accessor method). You'll need to look at Field.setAccessible and perhaps Field.getType.
Another approach is to generate another class for enumerating the annotated fields using a compile-time annotation processor. This requires a com.sun API in Java 5, but support is better in the Java 6 JDK (IDEs like Eclipse may require special project configuration).

Categories

Resources