I am converting an existing POJO to be an JAXB compliant. Everything works fine except for one of the getter method of the pojo where I need an additional logic specific to rendering XML. However, this getter is already called somewhere within the application and I cannot modify this method's behavior.
How do I normally deal with such method name collisions? Is there a way I create a separate method just for JAXB purpose adn mark the currentmethod as XMlTransient?
Thanks
Yes, exactly what you said would work. Make the one method #XmlTransient, then write another method and make it an #XmlElement(name="whatever element name").
You can put XmlAccessorType(XmlAccessType.FIELD) on the class. Then the JAXB annotations will be picked up from the field names, and not the method names. For example:
#XmlAccessorType(XmlAccessType.FIELD)
public class MyType {
#XmlElement String f1;
#XmlElement Integer f2;
// JAXB doesn't care about these:
public String getF1() {return f1;}
public String getF2() {return f2;}
public void setF1(String f1) {this.f1 = f1;}
public void setF2(Integer f2) {this.f2 = f2;}
}
Related
#Configuration
public class Product {
#Bean("xyz")
public String getMethod() {
return "abc";
}
}
#Component
public class Test {
String b;
Test(String xyz) {
this.b = xyz;
}
}
Is this any harm with this approach? I am trying to make change in the existing code where I am replacing the #Value with the getter as the method parameter. As I don't want to change the structure of the existing code I am trying to inject the method as bean as a replacement to #Value.
I suggest you to keep the #Value annotation instead of the whole #Bean configurations.
Why?
What if the getMethod()'s returned value needs to be changed very often? Everytime when you're changing something in the Product class, during build time it needs to be recompiled. What happens if the project is getting bigger and you're using this approach? It leads to longer build time and the more important thing is that this solution is not intuitive and it's hard to keep it clean. Don't think about complex solutions only to make the code look fancy. When you need to inject String values, the easiest approach is to create properties files (which won't get recompiled) and use the #Value annotation.
Now, if you want to add new methods without changing the structure of the existing code there are some patterns which you can apply like decorator pattern.
The main idea is simple: you're creating a decorator class which has an object of the type you need.
The easiest example (which you'll find everywhere on the internet) is the classic Shape example:
public interface Shape {
String someMethod();
}
#Component
public class CustomShape implements Shape { //implement the method here }
And here is the decorator:
public interface ShapeDecorator {
String someMethodExtended();
void someExtraMethod();
}
#Component
public class CustomShapeDecorator implements ShapeDecorator{
#Autowired
// #Qualifier - optional (only if you have more Shape implementations)
private Shape shape;
// now you can either:
// 1. provide new methods
#Override
public void someExtraMethod(){
System.out.println("Hello world!");
}
// 2. or you can EXTEND the Shape's "someMethod()" implementation
#Override
public String someMethodExtended(){
String oldString = this.shape.someMethod();
return oldString + " EXTENDED";
}
}
I have a Spring MVC controller like this:
#RequestMapping(value = "/search", method = RequestMethod.GET)
#ResponseBody
public Object grid(Search<MyFilter> search){
...
}
My Search object is like:
public class Search<F extends Filter> {
private int offset;
private int size;
private F filter;
//... getters/ setters
}
Filter is just an Interface. MyFilter is an implementation of Filter with some fields like name, title, etc.
I'm doing an HTTP GET to this controller with: /search?offset=0&size=10&filter.name=john
But spring can't instantiate MyFilter. I've tried to make Filter a normal empty class and MyFilter to extend it, but it's not possible either.
Is it possible to spring to instantiate the correct filter and then bind the values?
[TL;DR] No, Spring won't instantiate MyFilter from parametrized type.
The Search object is instantiated, when request arrives.
The problem is, that at runtime information about type parametrization is erased and converted to the most general type. I mean that at runtime your Search object effectively will look like:
class Search {
/*
* F is replaced by Filter since it is the most general type
* for <F extends Filter> parametrization.
* This will be the only Search class representation that compiler generates.
*/
private Filter filter;
//Rest of class body omitted
}
This is how generics works. Sicne Filter is an interface the object mapper has no clue how it should be resolved. You could guide object mapper how to resolve Filter into specific class based on i.e. additional type parameter (I belive that such case is answered here). But I don't think if mixing this with generics is good idea. It will lead to complex and confusing code.
You obviously depend on MyFilter implementation so you could use the approach from #DeezCashews suggestion. Or you could think of more flexible solutions. If all kinds of Filter are just containers of fields names and of wanted values you could do something like:
public class Search {
private int offset;
private int size;
private List<FieldPredicateTuple> filters;
//getters and setters omitted
}
public class FieldPredicateTuple {
String field;
String value;
//getters and setters omitted
}
And then call endpoint: /search?offset=0&size=10&filters[0].field=name&filters[0].value=john
I don't know how you want use those filters so I don't know what to propose. But I'd recommend to redesign this somehow.
I know this may not be exactly what you are looking for but if you are stuck perhaps consider extracting out the shared variables into its own class and then pass two parameters to your grid method instead of one. Spring Data has a Pageable class that is similar so perhaps you can look at that for inspiration. Then you can just pass a bean with the criteria and another bean with offset and size. Ex:
public Object grid(MyFilter f, Paged p);
public class MyFilter {
String name;
...
}
public class Paged {
int offset;
int size;
...
}
I want to write a function that, given an arbitrary java bean as an argument, returns an object that is a copy of that bean but that belongs to an anonymous subclass of the bean's type that contains an additional property. Let me illustrate with an example of what I have so far:
Foo.java:
import lombok.Data;
import lombol.AllArgsConstructor;
#Data
#AllArgsConstructor
public class Foo {
private String bar;
private String baz;
}
Garply.java:
public class Garply {
Foo fooWithQux(Foo foo, String quxVal) {
return new Foo(foo.bar, foo.baz) {
private String qux;
public String getQux() {
return quxVal;
}
};
}
}
This seems silly because I can never actually call getQux(), but a tool I work with uses reflection to successfully find the qux property and do what I want with it.
My issue is that I don't want to have separate fooWithQux() functions for each type that I want to be able to add the qux property to. Ideally I'd have something like beanWithQux() that accepts objects of arbitrary type. I think I could make this work with something like the following:
public T beanWithQux<T>(T bean, String quxVal) {
class BeanWithQux extends T {
private String qux;
BeanWithQux(T bean, String quxVal) {
// Here's where I'd like to copy all of the properties
// from the Bean into the BeanWithQux
qux = quxVal;
}
public getQux() {
return qux;
}
}
return BeanWithQux(bean, quxVal);
}
Here's where I'm stuck. I don't know to copy all of the properties from the given object into my new object. Anyone have ideas? Ideally there would be something I could do using lombok (I control the Foo class and can add annotations like #Builder if need be) as opposed to writing a bunch of reflection magic myself.
Thanks!
I think in this case using runtime bytecode weaving is a better approach, since you don't need to call the methods in your own codebase.
It seems Jackson uses reflection to write additional attributes directly into fields even if a #JsonCreator constructor was used and the field is marked as final.
Example:
public class Test {
static class X {
final String s;
#JsonCreator
public X(#JsonProperty("a") String a) {
s = "s";
}
public String getS() {
return s;
}
}
#org.junit.Test
public void ds() throws Exception {
ObjectMapper om = new ObjectMapper();
X x = om.readValue("{`a`:``, `s`: `t`}".replace('`', '"'), X.class);
assertEquals("s", x.s);
}
}
The assert will fail with org.junit.ComparisonFailure: expected:<[s]> but was:<[t]>.
Is this behavior documented anywhere? Is there anyway to disable this globally?
Also, I think this is a very dangerous design: if there are some value that should be read-only to the client, this effectively allows the client to set them even if the class is well designed according to normal immutable class guidelines.
First: yes, Jackson allows deserialization of all visible and not just those for which #JsonCreator property exists. So it is possible to set a smaller set of properties via constructor, and others via setters or fields. This may be needed for some cases like cyclic types.
As to how to prevent use of s for deserialization here. An obvious way is to add #JsonIgnore for field, although if so you will also need #JsonProperty for getS() to avoid both being removed.
But there are other settings as well, in MapperFeature.
ALLOW_FINAL_FIELDS_AS_MUTATORS: if you disable this, final fields are never used directly for deserialization
INFER_PROPERTY_MUTATORS: if you disable this, then neither fields nor setters are "pulled in" in cases where they are not otherwise visible (for fields, public is needed to be visible; for setters, even private is fine)
So may want to disable one or both settings.
I have the following situation: my application needs to save all the strings typed by the user capitalized on the database, no matter how the user types it, the application needs to capitalize everything before saving it.
I know I could just call the toUpperCase() method on every string before saving it, or call it on every setter method, but I really don't want to do that, I'm looking for a more automatic way to do it without having to change too much code on the application.
I'm using JSF, JPA2, Eclipselink and EJB3.
Does anyone have any suggestion?
You can use lifecycle event listeners for this. There are several ways to implement it:
1: default listeners:
public class StringCapListener {
#PrePersist
#PreUpdate
public void capitalize(Object o) {
// capitalize string attributes
}
...
For the capitalizing you will either need to use reflection (extracting all string fields and changing their value) or let your entities implement an interface.
If you are using the listener only on several entities, prefer using the #EntityListeners annotation on the entity classes. In order to use the listeners on all entities, use default listeners. Unfortunately, you can only define them in XML:
<entity-mappings ...>
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="com.example.StringCapListener">
2: inherited listener method
Let your entities derive from a BaseEntity of sorts. This base class can implement a listener method that is triggered on persist & update.
#PrePersist
#PreUpdate
public void capitalize(BaseEntity o) {
// capitalize string attributes
}
You will need to employ the same reflection magic to get and change all string attributes.
I'm thinking of an interface
public interface Processor<TResult, TInput> {
public TResult process(TInput input);
}
public class StringProcessor implements Processor<String, String> {
public String process(String input) {
return input.toUpperCase();
}
}
Then you'd call the interface on every string before persisting it
//...
public void persistString(String input) {
input = processor.process(input);
// Persistence logic
}