Spring web service maven-jaxb2-plugin complex input - spring

I need to create a client based on WSDL. I am using Spring 4 and Spring web service 2.2.0. Using maven-jaxb2-plugin I created classes and able to invoke web service. I am using object factory to create some objects, due to complex data type. Now I have a complex input. and I don't find appropriate methods in the generated class.
As per SOAP UI , the request body looks like
<soapenv:Body>
<zhin:ZHIN_HR_CA_EVALUATOR_SEND_RFCresponse>
<IN_DATA>
<IV_PERNR>4005002</IV_PERNR>
<IT_RATERS>
<!--1 or more repetitions:-->
<ArrayOfIT_RATERSItem>
<ORGTX>?</ORGTX>
<DESIG>?</DESIG>
<ENAME>N V S Ravi Kumar</ENAME>
<ZCPERNRT>?</ZCPERNRT>
<PERNR>4005001</PERNR>
<WEIGH>?</WEIGH>
<SEQUENCE>1St Evaluator</SEQUENCE>
</ArrayOfIT_RATERSItem>
</IT_RATERS>
<IV_APCAT>1</IV_APCAT>
</IN_DATA>
</zhin:ZHIN_HR_CA_EVALUATOR_SEND_RFCresponse>
</soapenv:Body>
Now i don't find a method to set ArrayOfITRATERS but I have getArrayOfITRATERSItem()
final ObjectFactory objectFactory = new ObjectFactory();
final INDATA requestValue = objectFactory.createINDATA();
requestValue.setIVPERNR(String.valueOf(id));
requestValue.setIVAPCAT(AppConstants.CA);
final ArrayOfITRATERS value = objectFactory.createArrayOfITRATERS();
value.set .....(not found ???)
requestValue.setITRATERS(value);
My autogenerated ArrayOfITRATERS class looks like
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ArrayOfIT_RATERS", propOrder = {
"arrayOfITRATERSItem"
})
public class ArrayOfITRATERS {
#XmlElement(name = "ArrayOfIT_RATERSItem", required = true)
protected List<ITRATERS> arrayOfITRATERSItem;
public List<ITRATERS> getArrayOfITRATERSItem() {
if (arrayOfITRATERSItem == null) {
arrayOfITRATERSItem = new ArrayList<ITRATERS>();
}
return this.arrayOfITRATERSItem;
}
}
I am not sure how to set the ArrayOfITRATERS
Any help is appreciated.

Does
getArrayOfITRATERSItem().add(myITRATERS);
solve your problem?
JAXB XJC does not generate setters for collections by default. Just add your items to the collection returned by the getter.

Related

How to use ref of schema as oneOf/anyOf responses of an endpoint using springdoc-openapi?

I'm using springdoc-openapi and I defined a few schemas using one of my classes (so they don't have individual classes). I've defined them using addSchemas in OpenAPI bean as mentioned in this issue:
https://github.com/springdoc/springdoc-openapi/issues/685#issuecomment-636028451
It's something like this:
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().components(new Components()
.addSchemas("ErrorOne", getSchemaWithDifferentDescription(ErrorObject.class, "ErrorOne")
.addSchemas("ErrorTwo", getSchemaWithDifferentDescription(ErrorObject.class, "ErrorTwo")));
}
private Schema getSchemaWithDifferentDescription(Class className, String description){
ResolvedSchema resolvedSchema = ModelConverters.getInstance()
.resolveAsResolvedSchema(
new AnnotatedType(className).resolveAsRef(false));
return resolvedSchema.schema.description(description);
}
Now I want to use these schemas in oneOf (or anyOf) using ref of them as possible responses of an endpoint. Something like this:
#PostMapping
#ApiResponses({
#ApiResponse(responseCode = "400",
content = { #Content(mediaType = "application/json",
schema = #Schema(oneOf = {"ErrorOne", "ErrorTwo"})) }
)
})
public HttpResponse myEndpoint(#RequestBody HttpRequest httpRequest) {
...
}
But the problem is that oneOf field in #Schema annotation only accepts a list of classes, and I can not use the ref of those schemas here.
Is there a way to link these schemas to oneOf/anyOf using their references in spring-doc?
And also I wanted to know is there a way to add some global responses as oneOf/anyOf responses for my endpoints (beside their own possible responses)?

How to write #ApiResponse which may return a Class or a List of that class using OpenAPI 3 Swagger in Spring Boot

As written in documentation we can use anyOf with #Schema if we want to define multiple responses.
#ApiResponse(responseCode = "201", description = "OK",
content = #Content(schema = #Schema(anyOf = {Product.class, Activity.class})))
My controller returns either a Product or a List<Product>. I would like to specify this in my OpenAPI 3 documentation.
I would like to know if it's possible.
If Yes, then how?
If No, then is there any workaround?
I don't only want to specify List.class. I want to specify List<Product>.
P.S.:- Searching on Google didn't get me any results that I can use.
Ok, thats a tough one.
Basically if you really want to return a List of Objects or one Object, then you can create a basic interface like this
public interface Response {
}
And then you can create your Object, which implements the response
public class Hello implements Response {
private String message;
public Hello(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
Finally we can create the List of our Object. For that we need to create a class, which extends the ArrayList and implements our Interface
public class HelloList extends ArrayList<Hello> implements Response {
}
After that we can just set our schema as implementation
#ApiResponse(responseCode = "200", description = "hello world", content = #Content(mediaType = "application/json", schema = #Schema(implementation = Response.class)))
On the Clientside you need to check the instance of the Response-Object, so that you can parse either the Object or the List
Response response = someCall();
if (response instanceof Hello) {
System.out.println(processHello((Hello) response);
}
if (response instanceof HelloList) {
System.out.println(processHelloList((HelloList) response);
}
This example works, but its very very complex und confusing. A better way to design your api, would be to return just the list. I don't see the benefit to seperate one object or the list of it.

Rest helper class instances best practice?

I'm new to rest webservice and have a novice q'.
I've created a rest class and would like to use helper classes to handle certain operations. So for example I've created the following service:
import statements...
#Path("/UserResources")
public class UserResource {
//Create Spring application context
static ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("classpath:/spring.xml");
private UserResourceHelper urh = new UserResourceHelper(); // this is the helper
class
UserProfileService userProfileService = ctx.getBean(UserProfileService.class);
#POST
#Path("/createUser")
#Consumes(MediaType.APPLICATION_JSON)
public Response createUser(#Context HttpServletRequest request, Object object) {
StringBuffer sb = new StringBuffer();
User user = userProfileService.findByPrimaryKey(object);
sb.append(urh.createUser(object));
return
Response.status(Status.CREATED.getStatusCode()).entity(result.toString()).build();
}
}
I have a couple of questions on this approach:
Is this the correct way to instantiate the helper class? Or should I create a constructor and instantiate the class there? for example:
public UserResource (){
urh = new UserResourceHelper();
}
On this approach will there always be a new instance of the
UserResourceHelper?
If so that would mean there will not be an issue
on concurrency correct? ie. 2 requests coming in at the same time
and the 1st object being received by the createUser method would
suddenly get replaced by the 2nd object that suddenly came in?
I'm using Hibernate for ORM. Is the way i've instantiated the entities as per my code sample correct?
Thanks for your assistance!

Spring multiple entity JSON serializers

I am looking for a way to create multiple json serializers for my entity. I have created service layer, custom serilizers and now I have problem with implementation of this things.
My Service class looks like:
#Service
class TeamsService(#Autowired private val teamsRepository: TeamsRepository) : ITeamsService{
override fun findAll(): String? {
var objectMapper = ObjectMapper()
var simpleModule = SimpleModule()
simpleModule.addSerializer(Teams::class.java, TeamsSerializer())
objectMapper.registerModule(simpleModule)
return objectMapper.writeValueAsString(teamsRepository.findAll())
}
}
And my Controller looks like:
#RestController
#RequestMapping("/v1")
class MainController(#Autowired private val teamsService: TeamsService) {
#GetMapping("/teams")
fun teams(): String? = teamsService.findAll()
}
Now I have problem that my response lost all headers and appears as text/plain not text/json, like it was before I added custom mapper.
I Was reading about projections but I am not sure if I should use them. I do not want to have query parameters in my url.
I found solution. The best way to do this is to use ModelMapper library. You can simply map entity to custom classes and serialize

Using Scala classes as DTOs in Spring MVC

In my project I'm using Spring + Scala.
Some of my Spring MVC controllers uses Spring feature for binding incoming HTTP parameters to DTO object. Like this:
#RequestMapping(value = Array("/", ""), method = Array(RequestMethod.POST))
def saveProduct(dto: MyDto): Iterable[MyDto] = {...}
And MyDto is simple scala class:
class MyDto extends Serializable {
#BeanProperty var id : Long = _
#BeanProperty var name: String = _
}
My problem is that I'm getting exceptions when trying to use Scala Option class for fields in MyDto:
class MyDto extends Serializable {
#BeanProperty var id : Option[Long] = None
#BeanProperty var name: Option[String] = None
}
Exception message is:
Failed to convert property value of type 'java.lang.String' to required type 'scala.Option' for property 'name';
What I can do to use Scala Options as type if fields in MyDto?
I am not a Scala expert, but here is one way:
Create a converter, along these lines:
import org.springframework.core.convert.converter.Converter
class TypeToOptionOfTypeConverter[T] extends Converter[T, Option[T]] {
override def convert(source: T): Option[T] = {
Some(source)
}
}
Register this converter with Spring MVC:
class WebConfig extends WebMvcConfigurerAdapter {
override def addFormatters(registry: FormatterRegistry): Unit = {
registry.addConverter(classOf[String], classOf[Option[String]], new TypeToOptionOfTypeConverter[String])
registry.addConverter(classOf[Long], classOf[Option[Long]], new TypeToOptionOfTypeConverter[Long])
}
}
That should be it, now your DTO should get cleanly mapped.
Spring has support for converting types using converters with its data binding. You will need to implement the converter so that Spring knows how to convert, for example, String to Option[String].
See:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert

Resources