exclude metaclass properties for groovy model classes in swagger - groovy

How do we exclude metaclass properties in model for "groovy" classes as Response? I have a Jax-Rs resource which returns a groovy object annotated with swagger #ApiModel.
I see too many groovy specific attributes in swagger ui. How do I exclude it from serialization?
#EqualsAndHashCode
#Document(collection = 'MongoCollection')
#CompileStatic
#ToString
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
#ApiModel(value = "Represents a document from mongo collection")
class Foo {
..
..
}
It seems to be using Jackson for pogo-json serialization? How do annotate my groovy class to exclude metaclass properties from getting into json serialized string?
I tried using JsonIgnoreProperties annotation but it didnt help.
#JsonIgnoreProperties(ignoreUnknown = true, value = ["MetaClass","MetaMethod"])

If using springfox, see springfox issues 752, found a way to resolve this :
docket.ignoredParameterTypes(groovy.lang.MetaClass.class)
A code example is:
#Configuration
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.ignoredParameterTypes(groovy.lang.MetaClass.class)
.select()
.apis(RequestHandlerSelectors.any())
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build();
}
}

This could be a bug in swagger as per https://github.com/wordnik/swagger-core/issues/519.
I switched from groovy to java classes for model objects to proceed as of now. Will work on creating a test for this issue when I get time.

https://springdoc.org/#groovy-support
Including this dependency with the springdoc-openapi-ui dependency will resolve the issue in the newer versions.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-groovy</artifactId>
<version>1.6.13</version>
</dependency>

Upgrading Swagger to a version >= 1.3.5 should resolve this.

Related

Mocking System class method using testng, mockito and powermock

I am currently writing tests to a legacy code which uses a function System.getenv("some_environment_variable")
I get a problem when I try to mock these variables by using mockito and powermock (used under testng framework)
What I did so far was
#BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("hello")).thenReturn("world");
}
#Test
public void test() {
assertEquals(System.getenv("hello"), "world");
}
But when I tried to run the code above i get the following error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object.
So Iv'e read and saw that this error raised when trying to mock a method with mocking the class itself, but this is not the case here.
After toying around with this for quite sometime, here's how I managed to do it.
In a nutshell, in order to get powermockito and TestNG to work with each other you have to do the following (quoting from the blog post whose link is shared below so that the answer is complete and will be useful even if the blog is not available at a later point in time)
Configure TestNG to use the PowerMock object factory : You can do this either via the attribute object-factory in your <suite> tag of your suite xml or via an #org.testng.annotations.ObjectFactory annotated method which returns the powermock's implementation of TestNG interface org.testng.IObjectFactory viz., org.powermock.modules.testng.PowerMockObjectFactory (or) by extending org.powermock.modules.testng.PowerMockTestCase
Use #PrepareForTest to prepare your static class for being mocked by PowerMockito
Please refer to this blog for more details.
Here's a working sample:
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.IObjectFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.ObjectFactory;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
#PrepareForTest(System.class)
public class SampleTestClass {
#BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("hello")).thenReturn("world");
}
#Test
public void test() {
assertEquals(System.getenv("hello"), "world");
}
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
}
I used the below dependencies for creating this sample
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
There is another JUnit library which may help you: system-rules, which will allow you to -- among other things -- set and restore environment variables. It is used in conjunction with JUnit #Rules

Cucumber-serenity not inject Steps

I´m using cucumber-selenium to run some integration tests. I manage to create the feature file and the Test class. But once that I´m in my Give method I see that the ScenarioSteps(ProjectMemberSteps) class that I define to talk with the object page is null.
I was expecting to be injected like JBehave does.
public class OrderTest extends StepsLibrary {
#Steps ProjectMemberSteps projectManager;//This one is null
#Before
public void beforeScenarios() throws Exception {
initializeDemoUIServer();
}
#Given("I open the login page")
public void openLoginPage(){
projectManager.openLoginPage();
}
}
This is the Scenario runner class for the test
/**
* Serenity story for login.
*/
#RunWith(CucumberWithSerenity.class)
#CucumberOptions(features="src/test/resources/features/order/order.feature",
glue = Order.BEHAVIOUR_PACKAGE)
public class Order {
public static final String BEHAVIOUR_PACKAGE = "com.behaviour.steps.serenity";
}
This is class ProjectMemberSteps is under steps/serenity/ as the documentation suggest.
I´m using Maven, and the libraries that I´m using are
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-junit</artifactId>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>core</artifactId>
<version>1.0.47</version>
</dependency>
Anyway this particular test I´m running with the IDE and not through Maven, but I was expecting that "ProjectMemberSteps" would be inject as JBehave use to do.
Any idea what´s wrong?
Regards.
I am also a newbie. I don't see any problem with your OrderTest.java class except it is unnecessarily extending a class called StepsLibrary. In Java-Cucumber, I don't extend any other class. Only exception is When
StepDefinition file(your OrderTest.java) delegates method calls to xxxxSteps.java class and which in turn delegates to xxxPageObject.java (which MUST extend PageObject class from Serenity import net.serenitybdd.core.pages.PageObject;)
I assume Before annotation is to repeat a scenario. Instead another alternative is Background keyword to be used in the feature file itself. I don't claim any advantage with this though.
Per me, Your Test Runner class should only give the package in which xxxxStepDefinitions.java resides, simply like glue = {"stepdefinitions"}, curly braces are optional I believe.
The rest looks perfectly OK to me. Including defining
#Steps ProjectMemberSteps projectManager;
Try one more time.

Mule Issue : More than one JAXBContext

We are facing one issue in our Mule Adapter related to JAXB context, needed some opinion on the same
We are using xpath to evaluate some expressions in the choice blocks in our adapter like below for instance,
<choice doc:name="Choice">
<when expression="//env:abc/env:Body/ref:dataelement/ref:/ref:element" evaluator="xpath">
......
</when>
Now, this works perfectly fine in our application but the problem arises when one of other team uses this Adapter as a jar in their application.
When they try to use this adapter, they are getting below error,
Message : More than one object of type class javax.xml.bind.JAXBContext registered but only one expected.
Type : org.mule.api.registry.RegistrationException
Code : MULE_ERROR--2
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/registry /RegistrationException.html.
After debugging with the help of loggers etc, we narrowed down to the choice block used above which is causing this particular issue. Also, googled a bit and found one of the posts pointing out the same issue.
Also, to confirm we commented out the choice block having xpath expression and the flow went ahead but broke again where was xpath used in some other way.
https://www.mulesoft.org/jira/browse/MULE-5926
Can anyone please suggest any suitable workaround to resolve this issue?
I agree with you. It is an unresolved issue in Mule.
One solution we have implemented is not define the jaxb context in the config you are providing in the jar file.
Along with the jar file, give instructions to the end application using it, to include the JAXB packages in their JAXB Context object definition.
This way there will be only one JAXB context and it will work smoothly.
Hope this helps.
This is a bit late however the solution that worked was
<mulexml:jaxb-context name=“JAXB_Context“ packageNames=“org.example.test1:org.example.test2“ doc:name=“JAXB Context1“ />
Please note that there must be no space between package names.
Thanks to: http://dominikbial.de/quicktipp-working-with-more-than-one-package-name-in-a-jaxb-context-config-in-mule-esb/
As of now we cannot add more than one JAXBContext in mule. As an alternative you can write your custom transformer.
I implemented something like
public interface MyAppJaxbObj2XmlComponent<I,O> extends
MyAppComponent<I,O>,Callable {
public O marshal(I input) throws Exception;
}
Abstart transformer
public abstract class AbstractMyAppJaxbObj2XmlComponent<I,O> implements
MyAppJaxbObj2XmlComponent<I,O>{
private Class<I> inputType;
public AbstractMyAppJaxbObj2XmlComponent(){
this.inputType = (Class<I>) new TypeToken<I>(getClass())
{}.getRawType();
}
public AbstractMyAppJaxbObj2XmlComponent(Class<I> type){
this.inputType = type;
}
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
I input = eventContext.getMessage().getPayload(inputType);
O output = marshal(input);
return output;
}
}
Your flow transformer this will load your needed jaxb during startup.
#Component
public class MyFlowJaxbObj2XmlComponent extends
AbstractMyAppJaxbObj2XmlComponent<RequestPayloadType,String> {
#PostConstruct
public void init() {
//Load your schema during startup
}
}
You can also implement a fluid interface as an alternative for this.

Spring Data Mongo: mapping objects using Jackson annotations

I'm using spring-data Mongo (1.3.3) as a mechanism for accessing Mongo.
My domain objects are written in Groovy and I use Jackson annotations to define properties and names:
#JsonProperty('is_author')
boolean author = false
#JsonProperty('author_info')
AuthorInfo authorInfo
When I persist one of my domain objects to Mongo, the JsonProperty annotation is ignored and the field is persisted using the standard object's field name.
By digging in the Spring Data Mongo documentation, I found out that the library expects a #Field annotation to modify the actual field's name in Mongo.
Is there a way to use only the Jackson annotations instead of using two annotations to achieve the same results. Maybe a "customized" version of MappingMongoConverter?
Since my application is in Groovy, I have used the new #AnnotationCollectorAST Transformation (http://blog.andresteingress.com/2013/01/25/groovy-2-1-the-annotationcollector-annotation/) to "merge" the Jackson and the Spring Data Mongo annotations. Here is how it looks like: simple and effective!
package com.someapp
import com.fasterxml.jackson.annotation.JsonProperty
import groovy.transform.AnnotationCollector
import org.springframework.data.mongodb.core.mapping.Field
#AnnotationCollector([Field, JsonProperty])
public #interface JsonMongoProperty {}
And here is how it is used:
#JsonMongoProperty('is_author')
boolean author = false
#JsonMongoProperty('author_info')
AuthorInfo authorInfo

JAXB is not picking up #XmlJavaTypeAdapter

I have the following class that I need to serialize as XML:
#XmlAccessorType(XmlAccessType.FIELD)
public class Position {
#XmlElement(name = "Quantity", required = true)
private DecimalQuantity quantity;
...
}
I have put an XmlJavaTypeAdapter on the DecimalQuantity class because I want it to be serialized simply as a BigDecimal without the DecimalQuantity wrapper.
#XmlJavaTypeAdapter(DecimalQuantityAdapter.class)
#Embeddable
public class DecimalQuantity {
private BigDecimal value;
...
}
Here's the very simple DecimalQuantityAdapter class:
public class DecimalQuantityAdapter
extends XmlAdapter<BigDecimal, DecimalQuantity> {
public DecimalQuantity unmarshal(BigDecimal val) throws Exception {
return new DecimalQuantity(val);
}
public BigDecimal marshal(DecimalQuantity val) throws Exception {
return val.getValue();
}
}
I have a unit test that shows that the adapter is working correctly. The following Order object that has a DecimalQuantity gets serialized correctly (notice that this test class looks almost identical to the Position class above):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Order")
public class Order {
#XmlElement(name = "Quantity", required = true)
private DecimalQuantity quantity;
...
}
This gets serialized as shown below - no wrapper around the decimal number - life is good!
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Order>
<Quantity>10.2</Quantity>
</Order>
The trouble starts when I try to use DecimalQuantity in other maven projects. For example, the Position class shown at the beginning of this post is in a different maven project. The web service that uses the Position class is in yet another maven project. When the web service tries to deserialize DecimalQuantity, it does not know what DecimalQuantity is and is not able to pick up the DecimalQuantityAdapter. This is the error I get:
Caused by: javax.xml.bind.JAXBException:
class org.archfirst.common.quantity.DecimalQuantity nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:648)
... 53 more
I have event tried to add the #XmlJavaTypeAdapter annotation on the attribute itself, but JAXB does not pick it up. The only way to get rid of the exception is to put an #XmlSeeAlso({DecimalQuantity.class}) on the Position class itself. However, this disables the adapter and I get the following (undesired) serialization:
<Quantity xsi:type="ns2:decimalQuantity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
Any idea where the problem is? I feel it has something to do with the visibility of JAXB annotations on DecimalQuantity and DecimalQuantityAdapter across packages/projects.
Thanks.
Naresh
Ok, I finally found the problem. My unit test was picking up the JAXB implementation in the Java runtime, whereas my real application (a web service) was picking up the JAXB implementation from GlassFish. Apparently the implementation bundled with GlassFish (2.2.1.1) cannot handle my use case. I proved it by forcing my unit test to use jaxb-impl-2.2.1.1.jar. Also it seems that the bug has been fixed in the latest JAXB implementation (2.2.3-1), but I am struggling to figure out how to replace GlassFish's implementation with this new version (see my post here).
Are you sure the problem is with the XmlJavaTypeAdapter for decimals, not the DecimalQuantity type. Because the exception you've posted is the one that happens when JAXB encounters a value of unknown class.
What happens if you omit the #XmlJavaTypeAdapter annotation? I know it probably can't work the way you intend, but what is the error message? Isn't it the same?
As you wrote the exception is gone when you added:
#XmlSeeAlso({DecimalQuantity.class})
I would leave the annotation in the code and try to find the reason why the adapter doesn't work.
Can you debug in the your XML adapter and/or add some trace output there, just to make sure the adapter really returns a non-empty String?

Resources