Java | variable value of attribute - java

I need to let a user of my program name an attribute of annotation, so I created fields in that class which could be managed by a user in main(), these fields should initialize a name attribute in the annotation of a getter, but Intellij IDEA tells that "Attribute value must be constant". Do you have any ideas how to do another way?
There is the code:
public class Model {
private String a;
private String b;
String nameA;
public User(String a) {
this.a = a;
}
public User(String a, String b) {
this.a = a;
this.b = b;
}
#XmlElement(name = nameA)
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
}

You can only use constant expressions in annotations.
It appears you want to map your property using a dynamic element name. For this change the type of JAXBElement<String> and use the #XmlElementRef annotation instead of #XmlElement. You can then construct your value as:
new JAXBElement(new QName(nameA), String.class, "myValue");

Related

Builder for existing classes

I have got the following scenario in which I got four classes autogenerated (in a JAR):
Class A{
B bEl = ...;
}
Class B{
C cEl = ...;
}
Class C{
D dEl = ...;
}
Class E{
E eEl=...;
}
Setting up those objects it is quite painful and error prone. Therefore, I was wondering if there is a better way to automatically construct a builder. I am aware of Lombok but I cannot edit that code and I cannot add the #Builder annotation.
Any recommendation?
If you are not allowed to change existing classes you can extend them:
public class Existing {
String a;
String b;
public Test(String a, String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
}
public class ExistingBuilder extends Existing {
#Builder
public ExistingBuilder(String a, String b) {
super(a, b);
// in case super class doesn't have all arguments constructor just call setters
// setA(a);
// setB(b);
}
}
So as you can see it's doable, but super class should have getters/setters or all args constructor.

Not able to save value In Mongo DB from Spring using MongoRepository

I am trying to do addition based on certain input's using Spring & save it in Mongo database.
As I have to do multiple addition :
1.So one way is to manually add the values and set them in bean and save it to the database.
OR
2.Just add them in getter of field & fetch when required.
When tried with second approach, I am not able to save the data in MongoDB
Please find sample code :-
Bean Class :
class Addition {
private double a;
private double b;
private double c;
private double d;
//getters and setters of a & b;
//getter of c;
public double getC() {
return a + b;
}
//getter of d;
public double getD() {
return getC() + a;
}
}
Interface which extends MongoRepository :
#Repository
public interface AdditionRepository extends MongoRepository<Addition, String> {
}
Calling Class :
#Controller
public class Add {
#Autowired
private AdditionRepository additionRepository;
#RequestMapping(value = "/add", method = RequestMethod.GET)
public void addNumbers(){
Addition addition = new Addition();
addition.setA(1.0);
addition.setB(2.0);
System.out.println(addition.getC()); //able to print expected value
System.out.println(addition.getD()); //able to print expected value
additionRepository.save(addition);
}
}
Data Saved in Mongo DB :
{
"_id" : ObjectId("581b229bbcf8c006a0eda4b2"),
"a" : 1.0,
"b" : 2.0,
"c" : 0.0,
"d" : 0.0,
}
Can anybody please let me know, where I am doing wrong, Or any other way of doing this.
The getters are not actually used for persistance. The framework is using the field instead:
"The fields of an object are used to convert to and from fields in the document"
http://docs.spring.io/spring-data/mongodb/docs/1.6.3.RELEASE/reference/html/#mapping-conventions
In your case, you could create a constructor which will take care of the computation:
class Addition {
private double a;
private double b;
private double c;
private double d;
public Addition(double a, double b){
this.a = a;
this.b = b;
this.c = a+b;
this.d = this.c + a;
}
}

NAME("name", true), what does true do here?

public enum Properties
{
NAME("name", true) ,
CATEGORY("category",false);
...
}
I have a enum like this.
And it is used like this:
myMap.put(Properties.NAME, name);
My question is, seems I am using the "name" from NAME?
What does that boolean value do here? "NAME("name", true) ,"
Thanks
Edited:
But my question is when I use it like this "Properties.NAME" I am getting "name", how can I actually get that "true"?
The constructor of your enum has two parameters: a String and a boolean. For example:
public enum Properties
{
NAME("name", true),
CATEGORY("category", false);
private final String s;
private final boolean b;
private Properties(String s, boolean b) {
this.s = s;
this.b = b;
}
public String getS() {
return s;
}
public boolean getB() {
return b;
}
}
Now, Properties.NAME.getS() returns "name" and Properties.NAME.getB() returns true.
Properties.NAME returns the object NAME of your enum Properties, and when you use it as a String, it will call the method toString() (like all objects in Java). And toString() call name() which returns the name of the object. Here "NAME".

Jackson: Printing Values as Keys in the JSON

Normally what we do in Jackson to print a class as JSON object is to define getter and setter like
public class MyClass
{
private Integer a;
private Integer b;
public myClass(Integer a, Integer b)
{
this.a = a;
this.b = b;
}
#JsonProperty
public Integer getA()
{
return a;
}
#JsonProperty
public Integer getB()
{
return b;
}
public void setA(Integer a)
{
this.a = a;
}
public void setB(Integer b)
{
this.b = b;
}
}
and this will return {"a":1,"b":2}
But can I get output as {1:2} instead of what I am getting before?
In order to achieve that, you need to write own code and pass accordingly. But output you showed is standard json format which you cannot change, but definitely you can change it with code.
If you do not care that output JSON is not valid you can write custom serializer for your POJO class. It could look like this:
class MyClassJsonSerializer extends JsonSerializer<MyClass> {
#Override
public void serialize(MyClass myClass, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
generator.writeStartObject();
generator.writeRaw(myClass.getA() + ":" + myClass.getB());
generator.writeEndObject();
}
}
Using:
#JsonSerialize(using = MyClassJsonSerializer.class)
class MyClass {
....
}
Since now, your POJO should be serialized to desired output.

Minimize JSON to deserialize and persist complex POJO with JPA/Hibernate

I have a fairly complex POJO that I need to deserialize from a JSON string and persist in a MySQL database. The following is a very simplified example class:
#Entity
#Table(name="a")
public class A{
private Long id;
private B b;
private C c;
private D d;
}
#ManyToOne
#JoinColumn(name="b_id")
public B getB(){
return this.b;
}
public void setB(B b){ this.b = b; }
#ManyToOne
#JoinColumn(name="c_id")
public C getC(){
return this.c;
}
public void setC(C c){ this.c = c; }
#ManyToOne
#JoinColumn(name="d_id")
public D getD(){
return this.d;
}
public void setD(D d){ this.d = d; }
Each class B, C, and D also have a number of fields and objects (some with even more required objects and fields) that can not be null according to the database schema, which I can't change. I can deserialize and persist this no problem, but the JSON required to do so is really massive. I only need to persist the deserialized A, so I really just need the _id fields from B, C, and D.
Right now my JSON is something like:
{
"id":1,
"b":{"id":2, ...},
"c":{"id":3, ...},
"d":{"id":4, ...}
}
where I have to fill in all the non-nullable database fields. What I would like to do is read a JSON string like:
{
"id":1,
"b_id":2,
"c_id":3,
"d_id":4
}
and just have Hibernate/JPA update those fields in the database. I think the real tricky part is that other classes/methods in my application will need the entire object hierarchy for reading from the database. The only time I can use just the _id fields is during the deserialization of the JSON. When this is the case, I only need to update the top-most object (A in my example) and some other trivial fields. In a perfect world, I can just throw some annotations on my class to solve this problem, but I haven't found anything capable of doing this.
Is this even possible? If so, can it be done with JPA/Jackson annotations?
Thanks!
If mapping the JSON directly to your entities is akward, I would simply make the translation from the incoming JSON string to your entities explicit via an intermediate object (call it a DTO if you will).
I also have a gut feeling that if you save associated object references (the #ManyToOnes) with only the id populated, Hibernate will in fact save the association correctly (root object here represents A):
{
"id" : 1,
"b" : {
"id" : 2
},
...
}
Make sure you don't cascade the persist operation for the b, c etc. fields.
You should create new classes which define only this fields which you want to deserialize. For example if you want to deserialize only ID your class could looks like this:
class JsonEntity {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonAnySetter
public void setUnknownProperties(String name, String value) {
//do nothing
}
#Override
public String toString() {
return String.valueOf(id);
}
}
In this example annotation JsonAnySetter do the trick. Now, you have to create some class which will be simulating your A class. For example:
class DtoA extends JsonEntity {
private JsonEntity b;
private JsonEntity c;
private JsonEntity d;
public JsonEntity getB() {
return b;
}
public void setB(JsonEntity b) {
this.b = b;
}
public JsonEntity getC() {
return c;
}
public void setC(JsonEntity c) {
this.c = c;
}
public JsonEntity getD() {
return d;
}
public void setD(JsonEntity d) {
this.d = d;
}
#Override
public String toString() {
return "A [id=" + getId() + ", b=" + b + ", c=" + c + ", d=" + d + "]";
}
}
Now when we have new JSON data model we can test it. For example we can parse below JSON:
{
"id":1,
"b":{"id":2, "p1":"v1", "p2":"v2"},
"c":{"id":3, "p3":"v3", "p4":"v4", "p5":"v5"},
"d":{"id":4, "p6":"v6"}
}
Deserialization example:
ObjectMapper objectMapper = new ObjectMapper();
DtoA a = objectMapper.readValue(json, DtoA.class);
System.out.println(a);
Above program prints:
A [id=1, b=2, c=3, d=4]
Now, you have to implement toA() method in DtoA class which could look like this:
public A toA() {
A a = new A(getId());
a.setB(new B(getB().getId()));
a.setC(new C(getC().getId()));
a.setD(new D(getD().getId()));
return a;
}
Let me know whether it works for you.

Categories