I have the following:
class A{
#XmlElement
String name;
//getters and setters
}
and
class B extends A{
#XmlElement
String height;
//getters and setters
}
finally I have
#XmlRootElement
class P{
#XmlElement
List<A> things;
//getters and setters
}
If I do
List<A> l = new ArrayList<A>();
l.add(new B('hello', 20)) //Add new B with height of 20 and name hello
P p = new P();
p.setThings(l); //Set things to list of B's.
and marshal P, I only get the field as part of things and not height.
I know that I can add #XmlSeeAlso(B.class) in A and it will all work.
But the issue is that I don't know all extended classes other than B, as A may be extended on runtime.
How do I dynamically define #XmlSeeAlso on runtime?
This depends on how you are creating your JAXBContext. The newInstance method can be called with an explicit list of all your classes, the documentation for that method also gives a similar example.
The client application must supply a list of classes that the new context object needs to recognize. Not only the new context will recognize all the classes specified, but it will also recognize any classes that are directly/indirectly referenced statically from the specified classes. Subclasses of referenced classes nor #XmlTransient referenced classes are not registered with JAXBContext. For example, in the following Java code, if you do newInstance(Foo.class), the newly created JAXBContext will recognize both Foo and Bar, but not Zot or FooBar:
class Foo {
#XmlTransient FooBar c;
Bar b;
}
class Bar { int x; }
class Zot extends Bar { int y; }
class FooBar { }
Edit: If you know at least the package names of potential jaxb classes you could also create a context given a context path.
If the above is not possible you could also create the list of classes at runtime, based on the object you want to serialize. I think it would be better to try to refactor your code to make this unnecessary. The code below is untested:
Set<Class> classes = new HashSet<Class>();
classes.add(p.getClass());
for (A a : p.getThings()) {
classes.add(a.getClass());
}
JAXBContext context = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
Note that #XmlSeeAlsocan also be annotated on a web service, see this post: http://weblogs.java.net/blog/kohlert/archive/2006/10/jaxws_and_type.html
This is useful if your base class doesn't have access to the subclasses (e.g. because they're in a different module), but your web service has.
Related
I have a parent abstract class "Parent" and child class "Child". I am using #SuperBuilder to generate builder APIs. Now, I want to perform some validations on the members of class "Parent" and "Child" as part of build. I couldn't find any solution to customize lombok super builder. As per lombok doc, it seems to be possible. Can someone please shed some light?
#SuperBuilder
public abstract class Parent {
int x;
int y;
int z;
int a;
}
#SuperBuilder
public abstract class Child extends Parent {
int b;
int c;
int d;
// I want something like
public static class ChildBuilder {
public Child build() {
Child child = // Get child somehow;
validate(child);
}
}
}
The generated code for #SuperBuilder is complex and loaded with type parameters. Therefore, it is advisable to delombok your class and use the output as a reference.
You can do this with this command:
java -jar path/to/lombok.jar delombok -p path/to/src/main/java/Child.java
The output will show what code lombok generates. I assume the Child class is not abstract (I think you have a typo in your questions). You want to customize the build() method, so you are interested in the ChildBuilderImpl, because this class contains that method. You can copy the class header to your source file and add your custom build() method:
private static final class ChildBuilderImpl extends Child.ChildBuilder<Child, Child.ChildBuilderImpl> {
#java.lang.Override
public Child build() {
// Do validation here, e.g.:
if (((Child.ChildBuilder<?, ?>)this).b == 0)
throw new IllegalArgumentException("b must not be 0");
return new Child(this);
}
}
Remark: I would prefer performing the validation in the constructor, because otherwise you could programmatically invoke the constructor without the values getting validated. However, customizing the #SuperBuilder constructor is not possible at the moment; it will be possible with the next lombok release. I'll update this question when it is released.
I've been at this since yesterday looking for a way to do this. What I have are hundreds of POJOs from a third party and need to apply properties to these based on business rules. I'm avoiding the altering of the POJOs because the third party could potentially recreate them thus creating a nightmare for managing files down the road.
What I'm attempting to do is to dynamically have a class extend another class.
For example.
POJO: Foo.java
package abc.service;
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
// end file
Mine: Bar.java
package abc.service;
public class Bar {
private String claim = "";
public Bar(){
claim = "You're correct";
}
public String getClaim(){
return claim;
}
}
// end file
Mine: TestMe.java
Trying here in a class separate from the POJOs to have a POJO extend another of my classes.
Is this beyond the abilities of JAVA?
package abc;
public class TestMe {
Foo f = new Foo();
Class c1 = f.getClass();
Bar b = new Bar();
Class c2 = b.getClass();
Class merged = c2.asSubclass(c1);
// Trying to call the Foo method
System.out.println(merged.getGreeting());
// Trying to call the Bar method
System.out.println(merged.getClaim());
}
Additionally what is going on is that JSON schemas are being created from the POJOs that are provided. But the POJOs are only based on an UPDATE record scenario. I'm looking for the best way to have the POJOs extend another class for CREATE record scenarios which is why I'm looking to dynamically have their POJOs extend my code when required.
Need to generate json schema for the POJOs for UPDATE
Need to verifying their json meets the POJOs requirements for UPDATE
Need to convert their json to the POJOs for UPDATE
Also,
Need to generate json schema for the POJOs for CREATE
Need to verifying their json meets the POJOs requirements for CREATE
Need to convert their json to the POJOs for CREATE
Using Jackson Mixin and the ObjectMapper I'm able to dynamically apply my code to the classes when creating the schemas but the issue I'm having is when trying to have the POJOs extend the class where Mixin is not going to solve the issue.
With plain Java: no, it can't be done.
You can change byte code, either in the build process, or at runtime. But it's hard, and there's not a lot of documentation.
AspectJ's declare parents expression is probably the easiest way to do it at build time.
If you want to do it at runtime, look at frameworks like asm, CGLib or ByteBuddy. But you will have to run the code from inside a custom ClassLoader or agent.
You can use composition instead of inheritance.
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
Your class
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public Foo getFoo(){
return foo;
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getFoo().getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
Or you can do you class a little bit different.
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public String getGreeting(){
return foo.getGreeting();
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
It is Not Possible.
Simply to put, JAVA at present(till latest version) does not have a provision to dynamically extend the class at runtime and load to JVM.
Instead of extending, you should use a design pattern. For example the Stategy Pattern. This allows you to change your strategy dynamicaly.
i have a class that is used widely in my project as some sort of field holder. Something like:
class A
{
private String field = null;
private String field2 = null;
private String field3 = null;
// and its generic Getters and Setters
}
In certain part of code i need add additional fields to this class. So i did this
class B extends A
{
private String fieldInB = null;
// and its Getters and Setters
}
in my function i thought i could easily do
public void foo( A a )
{
B b = (B)a;
}
And i could have all the fields written in aobject and i could easily set only field in b and use it. This seams like a common problem, but i just don't know how to do it except with an very ugly approach:
public B( A a )
{
// copy all the fields one at the time
}
You areconfusing different parts of Java:
B b = (B)a;
this is classical class cast, but to work with B class object you need:
1. be sure that a is of B class (check it with instanceof java keyword:
if (a instanceof B) {
B b = (B) a;
}
2. or wrap a in B class object (create B class object with copying fields from a).
PS in most of Java coding conventions it is recommended to fill fields by concrete values only (and not fill with default JavaVM values - nulls)
Comfortable way to copy A class fields to new instance:
public A (A a) {
this.field = a.field;
this.field2 = a.field2;
this.field3 = a.field3;
}
and for B class:
public B (A a) {
super(a);
}
Another way - some libraries that will work with A class and B class as with beans. Sample of this libraries you can find in Toilal's answer
You could use Dozer. It allows to map bean property values from one bean class to another.
Hai john Actually i didn't get your exact requirement. I recon the way you have written this code is not right.
Private variable cant be inherited.If you need to extend values to your subclass you should have declared those variables as public.
public B(A a)
{
super.field=a.field;
super.field2=a.field2;
super.field3=a.field3;
}
I have following classes
class A {
private Long id
private List<B> listB;
private C c;
...
}
class B {
private Long id
private A a;
private List<D> listD;
...
}
class C {
private Long id
private A a;
...
}
class D {
private Long id
private B b;
...
}
I need a copy of A, include all of it's properties except all id column.
I have 2 solutions:
1. Clone each object and set all of the ids null;
2. Make a constructor like this:
public A (A a){
//copy all properties except id
this.xxx = a.xxx;
...
}
But i need write so much code for this function, any one has some better method to implement this function?
Thanks a lot.
When you are saying Deep cloning of the object particularly the one of type Class A where you have an instance variable of a container type, you have below two widely known ways:
1) You Serialize and Deserialize the object.
2) You traverse through each method and call clone explicitely.
For first implementation, you may mark the id fields as transient and that should solve your purpose.
For second approach, you may override the clone method in each class where you set the id field as 0/-1) and call super.clone()
You can use Mapstruct , it's a powerful mapping library where you can configure all the fields exclusions for your specific class or nested class, without having to write all the getters/setters manually.
I personally use it for deep cloning jpa entities excluding ids or auditable fields.
Ex:
#Mapping(target="id",ignore=true")
EntityA cloneEntityAWithoutId(EntityA origin);
Mapstruct will generate for you the implementations using getters and setters of the EntityA, excluding the id field.
Obviously is a lot configurable, see the documentation I shared above.
Suppose i have a class A:
class A
{
private String value;
private B field;
public C otherField;
}
class C
{
private String otherValue;
}
class B
{
private String name;
}
Now, if i do a A.class.getClasses(), ill get an array with one element (the one which is public, something that makes sense based on what javadoc of Class.java says).
My question is: is there a way to get return a list of public + private fields of a class?
Thanks
The getClasses() method is not the correct way to access the Fields that are part of the A class. You need to use the getDeclaredFields() method to access an array of Field objects representing the fields in the class. From there, you'll need to set the accessibility of the field to true with a call to setAccessible(). There is more information available by looking into the Java Reflection API as well as here
You should notice, that getDeclaredField will only return the fields of the class which are declared in the class. Fields which are inherited from a super class will not be returned. To get all fields of a class you have to iterate over the super classes (using Class.getSuperclass()).