Java Spring Swagger Startuptime Startupbehaviour - java

I am having a Springboot application where I integrated Swagger for creating REST documentations.
When using swagger my startup time increases dramatically by factor 5. I'm having 30secs without swagger. 2min plus with swagger.
Also having the docket listed in the snipped underneath startup time becomes endlessly! - And this is a no-go.
My Problem is endless startup times + Exceptions regarding memory usage from google guava.
Why is it that way? What am I doing wrong? Where is the missing point? Why is the API not protecting me from very wrong setups?
It feels like that swagger is on the one hand a number one tool for documenting rest APIs but using it feels very ancient for me.
Some setup info (located at maven pom.xml):
- org.springframework.boot; spring-boot-starter-parent; 1.5.5.RELEASE
- io.springfox; springfox-swagger2; 2.9.2
- io.springfox; springfox-swagger-ui; 2.9.2
I somewhere picked up that googles guava library needs to be exchanged; which I did: https://github.com/springfox/springfox/issues/2616#issuecomment-412811912
Is swagger/springfox really so good to use for documenting an API coming from Spring? - What would be some alternatives to render documentation?
#Configuration
#EnableSwagger2
public class Swagger2UiConfiguration extends WebMvcConfigurerAdapter {
...
#Bean(name="restPublicSwaggerV1Api")
public Docket publicV1Api(BuildProperties build) {
final ApiInfoBuilder apiInfo = new ApiInfoBuilder()
.title(build.getName())
.description("Description for public API")
.version( build.getVersion() );
final long TIME = System.currentTimeMillis();
final Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName( "public-v1" )
.apiInfo( apiInfo.build() )
.select()
.apis( (wmrh)->{ // springfox.documentation.spring.web.WebMvcRequestHandler
final StringBuffer sb = new StringBuffer();
sb.append( wmrh.getClass().getTypeName() +"\n\t"+ wmrh );
final RequestHandlerKey rhk = wmrh.key();
boolean result = false;
for( String pathMapping : rhk.getPathMappings() ) {
sb.append( "\n\t-> "+ pathMapping );
result |= pathMapping.startsWith( "/api/public/" );
}
sb.append( "\n\t=>> "+ result +", time: "+ Util.formatTime( System.currentTimeMillis() - TIME ) +" after start." );
LOG.debug( sb.toString() );
return result;
} )
.paths( (p)->{ return true; } )
.build();
LOG.debug( "instantiated: {}", docket );
return docket;
}

Try using latest swagger-ui(swagger-js 2.1.17) as specified in
https://github.com/swagger-api/swagger-ui/issues/1919

Use #JsonIgnore in Many-To-Many relations

Related

Multiple SecurityScheme for swagger/open-api

I am facing a problem with the swagger UI 3 and the generated shcema.yml file
Currently, I have the configuration similar to this one:
#SecurityScheme(name = "security-oauth", type = SecuritySchemeType.OAUTH2,
flows = #OAuthFlows(
authorizationCode = #OAuthFlow(
authorizationUrl = "${authUrl}",
tokenUrl = "${tokenUrl}",
scopes = {}
)
)
)
This works as intended. Now, I want to add another #SecurityScheme so that I can also pass a cookie to the FE (an Angular App) and to get it back. However, the swagger UI and the generation for the schema.yml file fails.
#SecuritySchemes( {
#SecurityScheme(name = "security-oauth", type = SecuritySchemeType.OAUTH2,
flows = #OAuthFlows(
authorizationCode = #OAuthFlow(
authorizationUrl = "${authUrl}",
tokenUrl = "${tokenUrl}",
scopes = {}
)
)
)
}
)
With the annotation like this, the schema.yml is missing the secuirySchema part:
securitySchemes:
security-oauth:
type: oauth2
flows:
authorizationCode:
Am I missing something or is there a bug in the generation where it does not properly handle the #SecuritySchemes annotation?

How to integrate SAP Business One DI Server with JAVA

We are trying to integrate SAP Business One DI Server with JAVA. Checked help documents in SDK for DI Server but it is available for .NET only.
Don't want to use B1WS as we came to know that B1WS is not stable and has lots of bugs. Also checked for Python flask RESTful application but it has limited functionality.
The following code should allow you to connect to a "Company" object and from there perform your tasks (DI - NOT UI).
import com.sap.smb.sbo.api.*;
public static void main(String[] args)
{
ICompany company;
IDocuments document;
SBOCOMUtil util = new SBOCOMUtil();
company = util.newCompany();
try
{
company.setServer( "sqlservername" );
company.setCompanyDB( "dbname" );
company.setUserName( "manager" );
company.setPassword( "manager" );
company.setLanguage(com.sap.smb.sbo.api.SBOCOMConstants.BoSuppLangs_ln_English);
company.setDbUserName("sa");
company.setDbPassword("pwd");
company.setUseTrusted( new Boolean(false) );
int result = company.connect();
System.out.println("Company: " + company.getCompanyName());
// analyze connection result
if ( result != 0 )
{
System.out.println("Connection error: " + result);
}
else
{
System.out.println("Connection success, company name: " + company.getCompanyName() );
}
}
catch(SBOCOMException ex)
{
System.out.println(ex.getStackTraceString());
}
finally
{
company.disconnect();
}
}
Also take a look at the following path; "C:\Program Files (x86)\SAP\SAP Business One DI API\JCO\LIB" where you can find the wrapper for DI API also "C:\Program Files (x86)\SAP\SAP Business One SDK\Help" there should be a JCO zip with more details regarding the JAVA Approach. Generally, documentation is very poor regarding Java. Your best approach would be either the B1i or the COM solutions.
Regards,
enshadowed_

How to query mongoDB with TEXT (no java code) from Java, REST forbidden by OPS

I need a solution to parse a MongoDB shell query (or something close to) using Java...
I maintain a tool written in Java, used to move and transform data to and from different applications and tools.
I have been asked to implement something to query MongoDB... but am a total newbie in MongoDB, and...
It's a mess: Ops decided to not allow the rest communication, and deploying new specific Java code for each demand is not an option.
I try for some days to find a generic solution to request MongoDB from Java, simply giving a "request text" (yes, something like SQL) in order to make the solution easily reusable and maintainable.
One not bad solution is to use Nashorn and write a MongoDB dedicated code/request to be run. I already made the script module, it works on simple request but becomes a real pain in case of complex multi-level requests, and my users are not developers.
The second trail is to find a "Java accessible" MongoDB method to parse a "MongoDB shell" request, whatever it is. I have some results in a case of "Document" like the request but found nothing concerning "pipelines" starting with "[" as a JSON array... I saw here that hacking the mongoShell was not such a good idea, and I agree.
Any fresh idea ?
Thanks
//----------------------------
// Nashorn script
// inputObject contains configuration data
var credential= MongoCredential.createCredential( inputObject.user, inputObject.baseName, inputObject.passWord.toCharArray() );
var mongoClient= null;
try
{
mongoClient= new MongoClient( mongoServerList, java.util.Arrays.asList(credential) );
var mongoBase= mongoClient.getDatabase( inputObject.baseName );
var nbDocs= mongoBase.getCollection("messages_pnr").count();
print("nb docs= " + nbDocs );
var resultingDocuments= mongoBase.getCollection("messages").aggregate ( java.util.Arrays.asList (
new Document("$match", new Document("version", 2))
, new Document("$sort", new Document("_id", 1))
, new Document("$limit", 5)
, new Document("$project", new Document("_id", 0).append("identifier", "$identifier"))
) );
print("step 1");
var it_resultingDocuments= resultingDocuments.iterator();
print("step 2");
while( it_resultingDocuments.hasNext() )
{
print("step 3");
var currentResultingDocument= it_resultingDocuments.next();
print( currentResultingDocument.toJson() );
}
}
finally
{ if( mongoClient != null)
{ mongoClient.close();
}
}
//----------------------------------
// Java code for Document (found nothing for arrays)
MongoClient mongoClient= null;
try
{ // cnx
MongoCredential credential= MongoCredential.createCredential( this.getUser(), this.getBaseName(), this.getPassWord().toCharArray() );
mongoClient= new MongoClient( this.getMongoServersList(), Arrays.asList(credential) );
MongoDatabase mongoBase= mongoClient.getDatabase( this.getBaseName() );
long counter= 0;
Document requestDocument= Document.parse(mongoRequest);
MongoCollection<Document> collection= mongoBase.getCollection("messages_pnr");
AggregateIterable<Document> aggregate= collection.aggregate( Arrays.asList(requestDocument));
MongoCursor<Document> cursorIterable= aggregate.iterator();
while(cursorIterable.hasNext())
{
Document currentResult= cursorIterable.next();
String currentResultAsString= currentResult.toJson();
counter++;
System.out.println(counter + " " + currentResultAsString);
Utilities4Stream.copyFromByteArrayToOutputStreamsList(currentResultAsString.getBytes(), this.getResultOutputStreams());
}
}
finally
{
if(mongoClient != null)
{ mongoClient.close();
}
}
Our dev support department found that people from "dbschema.com" wrote a jdbc compliant layer above mongo client, and it works fine for me !
https://www.dbschema.com/mongodb-jdbc-driver.html

User names and passwords are logged in plain text during initialization of Atomikos

Our project relies on Atomikos to provide light-weight transaction management. However, we find that it logs the DB user name and password in plain text during initialization.
E.g.
2015-10-15 16:43:01,106 [http-bio-8080-exec-4] INFO com.atomikos.jdbc.AtomikosDataSourceBean - AtomikosDataSoureBean 'LAB_Oracle': initializing with [ xaDataSourceClassName=oracle.jdbc.xa.client.OracleXADataSource, uniqueResourceName=LAB_Oracle, maxPoolSize=8, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[URL=jdbc:oracle:thin:#***:1537:oocait01,user=***,password=**] loginTimeout=0]
Is there any configuration that can suppress the logging of these confidential information?
As far as configuration, you can set your threshold to WARN for log category com.atomikos.jdbc.AtomikosDataSourceBean. There are some examples for popular logging frameworks here. That would filter out that entire message.
If you only want to filter the confidential properties, you could create a subclass of AtomikosDataSourceBean and override the protected method printXaProperties(). Then you can filter out any confidential properties such as passwords.
package my.com.atomikos.jdbc;
import java.util.Enumeration;
import java.util.Properties;
public class AtomikosDataSourceBean extends com.atomikos.jdbc.AtomikosDataSourceBean {
private static final long serialVersionUID = 1L;
protected String printXaProperties()
{
Properties xaProperties = getXaProperties();
StringBuffer ret = new StringBuffer();
if ( xaProperties != null ) {
Enumeration it = xaProperties.propertyNames();
ret.append ( "[" );
boolean first = true;
while ( it.hasMoreElements() ) {
String name = ( String ) it.nextElement();
if ( name.equals ( "password" ) ) continue;
if ( ! first ) ret.append ( "," );
String value = xaProperties.getProperty( name );
ret.append ( name ); ret.append ( "=" ); ret.append ( value );
first = false;
}
ret.append ( "]" );
}
return ret.toString();
}
}
Since Atomikos will automatically detect the logging framework, which could vary depending how you test, package and deploy your application, using a subclass is probably more foolproof.
I submitted a pull request that could make it into version 4. We'll see.

JSF Flash arguments not carried over to next view (and no ?faces-redirect=true in browser URL)

We have a page that contains a command link:
<h:commandLink value="Go to Result Manager"
action="#{resultManagerDashboardHelper.navigateToTargetAll()}" />
This is supposed to redirect to the Result Manager view, secretly passing a list of two status flags representing "TODO" and "DONE", so that the filter will be set to "all statuses".
ResultManagerDashboardHelper.java:
#Named
#ViewScoped
public class ResultManagerDashboardHelper
{
...
public static final String SECRET_ARGS_KEY = "secretArgs";
...
private String navigateToPage( String outcome, String... args )
{
List<String> argsList = Arrays.asList( args );
FacesContext.getCurrentInstance().getExternalContext().getFlash().put( SECRET_ARGS_KEY, argsList );
String fullOutcome = outcome + "?faces-redirect=true";
System.out.println( "Setting flash secret args to " + argsList );
System.out.println( "Redirecting from '" + this.outcomeMapper.getCurrentOutcome() + "' to '" + fullOutcome + "'" );
return fullOutcome;
}
private String navigateToTargetPage( String... args )
{
return this.navigateToPage( "/view/resultmgmt/resultManager", args );
}
public String navigateToTargetAll()
{
return this.navigateToTargetPage( "TODO", "DONE" );
}
}
ResultManagerFilterHandler.java:
#Named
#ViewScoped
public class ResultManagerFilterHandler
{
...
// status flags secretly coming in via Flash from dashboard
private List<String> secretStatusFlags;
#Override
#PostConstruct
public void init()
{
...
#SuppressWarnings( "unchecked" )
List<String> secretStatusFlags = ( List<String> ) FacesContext.getCurrentInstance().getExternalContext().getFlash().get( ResultManagerDashboardHelper.SECRET_ARGS_KEY );
if ( secretStatusFlags != null )
{
System.out.println( "ResultManagerFilterHandler secret arguments have arrived via JSF Flash! Size = " + secretStatusFlags.size() );
}
else
{
System.out.println( "ResultManagerFilterHandler: NO secret arguments have arrived via JSF Flash!" );
}
// sits in view scope waiting to be picked up by search routine in ResultManager (also view-scoped)
this.secretStatusFlags = secretStatusFlags;
}
}
ResultManager.java:
#Named
#ViewScoped
public class ResultManager
{
...
#Inject
private ResultManagerFilterHandler filterHandler;
#Override
public void searchInitially()
{
// get Flash object from filter handler
List<String> statusFlags = this.getFilterHandler().getSecretStatusFlags();
System.out.println( "ResultManager statusFlags = " + statusFlags );
// if flash args have been passed, prefer that view over the standard one
if ( statusFlags != null && !statusFlags.isEmpty() )
{
System.out.println( "Flash search!" );
// set to today and decrypt the passed status flags (this is supposed to override the default search filter!)
this.filterHandler.setSelectedPeriod( EPeriod.TODAY );
this.filterHandler.calculateBeginEndDates( this.filterHandler.getSelectedPeriod() );
this.filterHandler.setTodoOnly( statusFlags.size() == 1 && statusFlags.get( 0 ).equals( "TODO" ) );
this.search();
}
else
{
System.out.println( "Non-flash search!" );
super.searchInitially();
}
}
}
When clicking the aforementioned link, the browser is redirected to the correct view. Then an event on the resultManager.xhtml page
<f:event type="preRenderView"
listener="#{resultManager.searchInitially}" />
calls the searchInitially method, which is supposed to pick up the stored status flags from the ResultManagerFilterHandler bean. However the Flash arguments aren't there:
18:58:42,840 INFO [] (134) Setting flash secret args to [TODO, DONE]
18:58:42,840 INFO [] (134) Redirecting from '/view/dashboard' to '/view/resultmgmt/resultManager?faces-redirect=true'
18:58:43,039 INFO [] (135) ResultManagerFilterHandler: NO secret arguments have arrived via JSF Flash!
18:58:44,350 INFO [] (135) ResultManager statusFlags = []
18:58:44,350 INFO [] (135) Non-flash search!
Q:
What am I doing wrong? How do I get it to work?
Note that ?faces-redirect=true URL parameter isn't appended to the URL... I wonder why?? Might this be the reason for the empty flash? Or is it normal behavior?
We're using Mojarra 2.1.22, which is known to have some issues keeping Flash instances longer, but this is something I'd like to solve later.
PS: sorry for the complex example, in reality it is even more complex... :-/
PPS: oh and never mind the combination of #Named and #ViewScoped, we're using Seam 3, which replaces the JSF #ViewScoped with a CDI-compatible one.
First of all, I encourage you not to use two #ViewScoped beans for the same view. You can achieve this functionality either carrying the functionallity of ResultManagerFilterHandler to your ResultManager. If you however want to reuse ResultManagerFilterHandler methods in other beans, just use a plain class (not managed by JSF) and make your managed beans extend from it.
On the other hand, there's no point for using 2.1.22 anymore. Just go with latest 2.1.x branch version, it'll be fully compatible with the code you have and brings lots of bug fixes, specially the ones related with flash scope.
Related with faces-redirect="true", keep in mind the Faces Servlet processes your redirection url before sending it to the browser. This parameter only tells that you want to perform a redirection, the servlet will remove it after evaluating.
See also:
Understand Flash Scope in JSF2
Exception about flash in Mojarra JSF

Categories

Resources