I have a JAX-RPC (Java) web service that needs to return a complex polymorphic value. To be more specific, the class structure is something like this:
abstract class Child {
}
class Question extends Child {
private String name;
// other fields, getters, and setters
}
class Section extends Child {
private String label;
private Child[] children;
// getters and setters
}
class Quiz {
private Child[] elements;
// getter and setter
}
My web service has a method that returns a Quiz, which of course may contain Questions and Sections which may contain Questions and other Sections, and so on and so forth. However, when I generate the WSDL, only Child and Quiz make it in. When I call the web service, I get back a Quiz element with the right number of children, but they're all Child elements, and they're all empty.
Is there a good way to make this work, short of just returning XML as a String?
Before anyone asks, due to circumstances beyond my control, I cannot use JAX-WS.
I don't think JAX-RPC supports polymorphism in that way. I had a similar problem, and had to work around it by creating a class that had just two members - one for each of the two classes that could possibly be returned - and only populating one depending on the type I wanted to return. So in your case:
class Child
{
private Section section;
private Question question;
// Constructor, etc...
}
class Question
{
private String name;
// other fields, getters, and setters
}
class Section
{
private String label;
private Child[] children;
// getters and setters
}
class Quiz
{
private Child[] elements;
// getter and setter
}
Which requires the client to check which member of child is populated, and is horribly ugly, I know.
Maybe someone is still looking for it, it can be done in axis 1.4:
Add next line into your section of axis web service deployment file (wsdd):
<parameter name="emitAllTypesInWSDL" value="true" />
Modify your task in ant build file to include 'extraClasses':
<axis-java2wsdl ... extraClasses="..."></axis-java2wsdl>
In extraClasses mention all classes which will be passed, since axis aren't able to guess which childs you'll be passing/returning as parameters.
Done, now you can pass derivated classes in methods accepts parent classes. Etc:
// server side class A { ...}
class B extends A {...}
class C extends A {...}
// ws
class wsAxis { public void processPolymorphCall(A obj); }
// client side
wsAxis.processPolymorphCall(new C());
// this will work now, as much as returning derivated classes in place of base class.
Related
I have the following classes
The first level of hierarchy:
abstract class Parent2 {
private P2_Param1 p2_param1;
private P2_Param2 p2_param2;
protected Parent2(P1_Param1 p1_param1) {
p2_param1 = p1_param1.something()
p2_param2 = p1_param1.somethingElse()
}
}
Second level:
abstract class Parent1 extends Parent2 {
private P1_Param1 p1_param1;
protected Parent1(P1_Param1 p1_param1) {
super(p1_param1);
this.p1_param1 = p1_param1;
}
}
And hundreds of classes that look like this:
class Child extends Parent1 {
private C_Param1 c_param1;
private C_Param2 c_param2;
private C_Param3 c_param3;
private C_Param4 c_param4;
// ... many more parameters here
public Child(P1_Param1 p1_param1) {
super(p1_param1);
}
}
These classes were used like this for a long time - child fields were used only to represent schema.
Now things changed and Child fields need to hold values.
I'd like to create as few changes in ChildX classes as possible and avoid implementing constructors that take all child parameters + p1_param1.
Ideally, it'd be great to use Lombok annotations or add some code in the parent classes.
I was thinking about instantiating the child class as it was before and using toBuilder = true to copy and fill values:
var child = new Child(p1_param1)
.toBuilder()
.c_param1(c_param1)
.build();
I tried to use the #SuperBuilder(toBuilder = true) annotation, but now I have an access to fill fields from parent classes (e.g. p2_param2) and I would like to avoid that.
Is my approach valid? Can I somehow make the parent fields not accessible via public child builder methods?
I found a solution to my question:
The answer is to use the Delombok option and then remove all methods from the generated (#SuperBuilder) parents' builders.
I doing a Vaadin (7.10) app, and in some view, I would need to add an "special" nested property into the container. For the sake of the application, we're using BeanItemContainer and Grid. I have some class that stores a List of another POJO(s), and I would need to use one property inside those second POJO to filter the grid. A basic example of the config would be:
public class A {
private String property1;
private String property2;
//There are too getters and setters for this two properties
}
public class B { //This class stores a list of As
private String name;
private List<A> list;
//Getters and setters too
}
These are my two basic classes, wich I use to store data. The Vaadin code to show data would be:
Grid grid = new Grid();
BeanItemContainer<B> container = new BeanItemContainer<>(B.class);
//////////////
container.addNestedContainerProperty("list.property1");
//This OBVIOUSLY doesn't work, because property1 is not part of List
/////////////
grid.setColumns("name");
grid.setContainerDataSource(container);
So, my question is:
Is possible to show in Grid this property1 without changing from BeanItemContainer?
This seems like a job for a generated property.
BUT: it still requires changing from BeanItemContainer or more detailed it requires wrapping it. Anyway it was not a problem when i did it (years ago).
For this you need GeneratedPropertyContainer. It is a wrapper for other containers that need generated properties added.
GeneratedPropertyContainer container =
new GeneratedPropertyContainer(yourBeanItemContainer);
Add generated properties to that container
container.addGeneratedProperty("property1"
,new PropertyValueGenerator<String>() { ... });
Above mentiond PropertyValueGenerator should then return String that you possibly choose from some pojo A.
Vaadin API for PropertyValueGenerator
Update considering filtering: PropertyValueGenerator overrides method
modifyFilter(Container.Filter filter)
Return an updated filter that should be compatible with the underlying
container.
For example: if you just pick the first pojo A from list and its property1 the you could implement this to make the filter to filter out all Ba whose first As property1 does not match.
Aside from #pirho's answer, which seemed brilliant to me, there's another possibility:
You can create a derivated list in B (if you have access to it) of the properties you want to filter like this:
public class B {
//Other already declared properties
private List<String> derivatedStringList;
//Here you declare getters and setters
public void setList(List<A> l) {
this.list = l;
this.derivatedStringList = l.stream()
.map(a -> a.getProperty1())
.collect(Collectors.toList());
}
//Only declare getter, because it's a -->generated<-- property
public List<String> getDerivatedStringList() {
return derivatedStringList;
}
}
And then use it in your Grid, filters... Wherever you want.
I have an object model that is handling relations between types. These references sometimes loop back around on themselves, and to stop that (in say a REST call) I am using things like the #JsonIgnore tag to make sure I don't get infinite nest recursion.
The issue with this is more a question of context. If I want an item to be included in one spot but not another (if being nested), #JsonIgnore stops it from both spots.
Example:
public class A implements Serializable{
Set<B> bs;
Set<C> cs;
...
}
public class B implements Serializable{
String name;
Set<D> ds;
...
}
public class C implements Serializable{
B b;
...
}
public class D implements Serializable{
...
}
If A is my main container which is transporting the objects. In the context of B as listed in A, I want the Set<D> to show. When an object B is used in context of C however, I want to hide Set<D> and only show the name.
If I were to mark #JsonIgnore on B.ds it wouldn't show up in either case. Is there some annotation/customization I can put on C.b to ignore inner attributes? #JsonIgnore("ds") or something? Is there another way to handle this entirely?
You can annotate the fields with #JsonView and then specify the serialization view you want to use in particular circumstances. Here's a post about using it with SpringMVC but the approach would be the same regardless.
So in your specific example,
public class View {
interface Full {}
interface Summary {}
}
public class B implements Serializable{
#JsonView({View.Summary,View.Full})
String name;
#JsonView(View.Full)
Set<D> ds;
}
I have an abstract base class with existing subclasses that is mostly used for defining a number of common fields and associated methods. I have a separate concrete class that "organically evolved" (i.e., bad design due to unforeseen feature requests) to end up with all the same fields defined in that abstract subclass.
Is there any way of having that separate class extend the abstract class and carry over the data of existing stored instances of that separate class? I would like to use InheritanceType.SINGLE_TABLE, but if another strategy makes it easier or possible, I guess that's fine too.
Also, those are entities referenced in other entities (OneToMany). Is that a problem? Hibernate uses only one global sequence for assigning entity ids - so it should in theory be possible to not break those references even if the data is moved to another table, right?
Already tried a few things, but no luck so far (e.g., add the "extend" to the separate class, hard-code it to use the same table as the base class, manually add a field for the discriminator...).
I am also happy about any pointers to examples/docs on how to carry out class hierarchy changes and other data model changes with JPA/Hibernate without losing data!
So, here's a simplified example of the situation. Base is the abstract base class that already has sub-classes.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "Base")
public abstract class Base {
private long persistenceId;
private String privateField;
#Id
#GeneratedValue
public long getPersistenceId() {
return persistenceId;
}
public void setPersistenceId(long persistenceId) {
this.persistenceId = persistenceId;
}
[...]
}
#Entity
public class SubclassToBe {
private long persistenceId;
private String privateField;
private String someFieldNotInBaseClass;
#Override
#Id
#GeneratedValue
public long getPersistenceId() {
return persistenceId;
}
#Override
public void setPersistenceId(long persistenceId) {
this.persistenceId = persistenceId;
}
[...]
}
The goal would be to have SubclassToBe inherit from Base, removing the definitions of shared fields but keeping the information stored there. And at the same time, not break references to the persistence ids of SubclassToBe objects that are used in other objects as part of OneToMany relations.
I'm working on GAE-based applications, which uses JDO to access datastore. I need to implement polymorphic relationship between persisted objects.
There's abstract parent class:
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class Parent {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id;
// ....
And several child classes:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class Child extends Parent {
// ....
Also, there's one more class, which should have reference to one of child classes. According to "Polymorphic Relationships" section of "Entity Relationships in JDO" article, the best way to implement such relationship is to store key of an object, so this class looks in the following way:
#PersistenceCapable (identityType = IdentityType.APPLICATION)
public class OtherClass {
#Persistent
private String reference;
// ....
I retrieve string key of referenced object from instance of OtherClass. Then I would like to obtain referenced object itself: it's an instance of one of Parent subclasses. BUT:
If I do it with pm.getObjectById(oid) method:
Object object = pm.getObjectById(reference);
JDOObjectNotFoundException exception is thrown (javax.jdo.JDOObjectNotFoundException: No such object FailedObject:...).
If I do it with getObjectById(class, key) method:
Parent object = pm.getObjectById(Parent.class, reference);
FatalNucleusUserException exception is thrown (org.datanucleus.store.appengine.FatalNucleusUserException: Received a request to find an object of kind Parent but the provided identifier is the String representation of a Key for kind Child)
What is correct way to retrieve instance of one of subclasses referenced in another entity?
UPDATE: I found this thread in GAE google group, but frankly it did not help me a lot.
I found the same problem with JDO and App Engine, so I started a project that implements a workaround for this. https://code.google.com/p/datanucleus-appengine-patch/
My first test with the code I have now looks okay, feel free to try it out at give me some feedback.
Actually my workaround may solve your problem 2 ways.
I implemented a getObjectById(class, id) that also looks for kinds that are instances of the provided class.
I implemented a getObjectById(oid) that does some special handling of lookup if oid is of type com.google.appengine.api.datastore.Key, then it will figure out the correct class to return.
I added a new annotation #PolymorphicRelationship that will make is easy to handle to workaround that App Engine describes, with storing the keys. Sample shown below:
#Persist
public Collection<Key> myChildKeys;
#NotPersistent
#PolymorphicRelationship(keyField ="myChildKeys")
public Collection<TestChild> myChildren;
I'm using this rather cancerous and smelly anti-pattern to get around this limitation of JDO/App Engine.
#JsonIgnore
#Persistent(mappedBy="account")
private List<XProvider> xProviders;
#JsonIgnore
#Persistent(mappedBy="account")
private List<YProvider> yProviders;
// TODO: add extra providers here and in getProviders() below...
And then to get the collection:
public List<XProvider> getXProviders() {
if (xProviders == null) {
xProviders = new ArrayList<XProvider>();
}
return xProviders;
}
//etc with other getters and setters for each collection.
public List<Provider> getProviders() {
List<Provider> allProviders = new ArrayList<Provider>();
// TODO: add extra providers here...
allProviders.addAll(getXProviders());
allProviders.addAll(getYProviders());
return allProviders;
}
It's a bad solution, but any port in a storm...
(Also relates a little to this bug, using interfaces as the collection type http://code.google.com/p/datanucleus-appengine/issues/detail?id=207)
App Engine's JDO layer doesn't currently support polymorphism. In fact, I'm not sure if JDO supports it in general or not.