Issues with the REST client in Scala - apache

I am creating a Scala REST client using Apache HttpClient.
Here is my code.
import java.io._
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.DefaultHttpClient
val output = getRestContent(myURL)
/**
* Returns the text content from a REST URL. Returns a blank String if there
* is a problem.
*/
def getRestContent(url:String): String = {
val httpClient = new DefaultHttpClient()
val httpResponse = httpClient.execute(new HttpGet(url))
val entity = httpResponse.getEntity()
var content = ""
if (entity != null) {
val inputStream = entity.getContent()
content = io.Source.fromInputStream(inputStream).getLines.mkString
inputStream.close
}
httpClient.getConnectionManager().shutdown()
return content
}
The problem is that Source is marked in red in io.Source. It says Cannot resolve symbol source. Moreover import java.io._ is marked as unused. How to solve this issue?

You should:
replace import java.io._ with import scala.io.Source
replace io.Source.fromInputStream(...) with Source.fromInputStream(...)

Source class is not in java IO library
It is in
scala.io.Source
add this line and it will work
import scala.io.Source

Related

Kotlin Annotation processor doesn't add import for generated files

I have an Annotation-processor, which should generate a class MyGeneratedClass containing a variable of another class MyEntity.
My code inside the processfunction:
val elementsWithAnnotation = roundEnv.getElementsAnnotatedWith(MyClass::class.java)
if (elementsWithAnnotation.isEmpty()) {
return true
}
val fileName = "MyGeneratedClass"
val packageName = "me.myname.sdk.generated"
val classBuilder = TypeSpec.classBuilder(fileName)
for (element in elementsWithAnnotation) {
val ann = element.getAnnotation(MyClass::class.java)
println("package: "+ ann.javaClass.packageName)
val variableBuilder =
PropertySpec.varBuilder(
name = element.simpleName.toString(),
type = ClassName("", element.asType().asTypeName().asNullable().toString()),
).initializer("null")
classBuilder
.addProperty(variableBuilder.build())
}
val file = FileSpec.builder(packageName, fileName)
.addType(classBuilder.build())
.build()
val generatedDirectory = processingEnv.options[KAPT_KOTLIN_GENERATED_OPTION_NAME]
file.writeTo(File(generatedDirectory, "$fileName.kt"))
return true
But the generated code misses the import MyEntity
package me.myname.sdk.generated
class MyGeneratedClass {
var MyEntity: MyEntity? = null
}
When looking inside the generated file, IntelliJ suggests me to import MyEntity, which resolves the error. But how can I achieve, that the import MyEntity statement is being added when generating the file?
looking at the kotlinpoet documentation https://square.github.io/kotlinpoet/1.x/kotlinpoet/kotlinpoet/com.squareup.kotlinpoet/-class-name/index.html
seems like the first argument in your code, which is a empty string is the package name you are missing in the generated code.
in my experience kotlinpoet is much happier to generate code that in in packages. it sometimes does silly things with types in the root/default package.

How to start a #Bean with custom parameters after an event had happened with spring for tests?

I am working on adding RepositoryTests with TestContainers framework for a project that uses R2dbc and I am running into the following situation:
1 - On the main project I set r2dbc url (with port and hostname) on application.yaml file and spring data manages everything and things just work.
2 - On the Tests however, I am using TestContainers framework more specifically DockerComposeContainer which I use to create a mocked container using docker-compose.test.yaml file with the databases I need.
3 - This container creates a port number on the go I define a port number on my docker-compose file but the port number that DockerComposeContainer will provide me is random and changes everytime I run the tests, what makes having a static url on application-test.yaml not an option anymore.
So I need to dinamically create this bean R2dbcEntityTemplate at run time and only after the DockerComposeContainer will give me the port number. So my application can connect to the correct port and things should work as expected.
I tried to create this class:
package com.wayfair.samworkgroupsservice.adapter
import io.r2dbc.mssql.MssqlConnectionConfiguration
import io.r2dbc.mssql.MssqlConnectionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.ConstructorArgumentValues
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.GenericBeanDefinition
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Profile
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.data.r2dbc.dialect.SqlServerDialect
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.stereotype.Component
#Component
#Profile("test")
class TemplateFactory(
#Autowired val applicationContext: ApplicationContext
) {
private val beanFactory = applicationContext.autowireCapableBeanFactory as BeanDefinitionRegistry
fun registerTemplateBean(host: String, port: Int) {
val beanDefinition = GenericBeanDefinition()
beanDefinition.beanClass = R2dbcEntityTemplate::class.java
val args = ConstructorArgumentValues()
args.addIndexedArgumentValue(
0,
DatabaseClient.builder()
.connectionFactory(connectionFactory(host, port))
.bindMarkers(SqlServerDialect.INSTANCE.bindMarkersFactory)
.build()
)
args.addIndexedArgumentValue(1, DefaultReactiveDataAccessStrategy(SqlServerDialect.INSTANCE))
beanDefinition.constructorArgumentValues = args
beanFactory.registerBeanDefinition("R2dbcEntityTemplate", beanDefinition)
}
// fun entityTemplate(host: String = "localhost", port: Int = 1435) =
// R2dbcEntityTemplate(
// DatabaseClient.builder()
// .connectionFactory(connectionFactory(host, port))
// .bindMarkers(SqlServerDialect.INSTANCE.bindMarkersFactory)
// .build(),
// DefaultReactiveDataAccessStrategy(SqlServerDialect.INSTANCE)
// )
private fun connectionFactory(host: String, port: Int) =
MssqlConnectionFactory(
MssqlConnectionConfiguration.builder()
.host(host)
.port(port)
.username("sa")
.password("Password123##?")
.build()
)
}
And this is how my db initiliser looks like:
package com.wayfair.samworkgroupsservice.adapter.note
import com.wayfair.samworkgroupsservice.adapter.DBInitializerInterface
import com.wayfair.samworkgroupsservice.adapter.TemplateFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.testcontainers.containers.DockerComposeContainer
import org.testcontainers.containers.wait.strategy.Wait
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import java.io.File
#Testcontainers
class NoteTagDBInitializer : DBInitializerInterface {
#Autowired
override lateinit var client: R2dbcEntityTemplate
#Autowired
lateinit var factory: TemplateFactory
override val sqlScripts = listOf(
"db/note/schema.sql",
"db/note/reset.sql",
"db/note/data.sql"
)
init {
factory.registerTemplateBean(
cont.getServiceHost("test-db-local_1", 1433),
cont.getServicePort("test-db-local_1", 1433)
)
}
companion object {
#Container
val cont: KDockerComposerContainer = KDockerComposerContainer("docker-compose.test.yml")
.withExposedService(
"test-db-local_1", 1433,
Wait.forListeningPort()
)
.withLocalCompose(true)
.also {
it.start()
val porttt = it.getServicePort("test-db-local_1", 1433)
print(porttt)
}
class KDockerComposerContainer(yamlFile: String) :
DockerComposeContainer<KDockerComposerContainer>(File(yamlFile))
}
}
I am not getting errors when trying to start this template factory with no useful error message,
But to be honest I don't know anymore if am putting effort into the correct solution, does anyone have any insight on how to pull this off or if I am doing anything wrong here?
So to summarise for production app it is fine, it starts based off of the url on application.yaml file and that's it, but for tests I need something dinamic with ports that will change everytime.
Thank you in advance ))
Spring already has a solution for your problem.
If you're using a quite recent Spring version (>= 5.2.5), you should utilize #DynamicPropertySource in order to adjust your test configuration properties with a dynamic value of the container database port. Read official spring documentation for more details and kotlin code examples.
If you're stuck with an older Spring version, the interface you need is ApplicationContextInitializer. See this spring github issue for a small example.

XDocReport converting odt to pdf how to set proper locale

I'm trying to convert some *.odt file to *.pdf using IXDocReport.
Here is the hypothetical content of the *.odt file: ${amount?string.currency} to be paid
Here is the code I do conversion with (you can run it in kotlin REPL):
import fr.opensagres.xdocreport.converter.ConverterTypeTo
import fr.opensagres.xdocreport.converter.ConverterTypeVia
import fr.opensagres.xdocreport.converter.Options
import fr.opensagres.xdocreport.document.IXDocReport
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry
import fr.opensagres.xdocreport.template.TemplateEngineKind
import java.io.ByteArrayInputStream
import java.io.File
val options: Options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.ODFDOM)
val content: ByteArray = File("/home/sandro/tmp/report.odt").readBytes()
val templateId: String = "someId"
val registry: XDocReportRegistry = XDocReportRegistry.getRegistry()
val data: MutableMap<String, Any> = mutableMapOf("amount" to 10)
ByteArrayInputStream(content).use { input ->
val report: IXDocReport =
registry.loadReport(input, templateId, TemplateEngineKind.Freemarker, true)
val tmpFile: File = createTempFile("out", ".pdf")
tmpFile.outputStream().use { output ->
report.convert(data, options, output)
println(tmpFile.toString())
}
}
and the result is the pdf file with string $10.00 to be paid
How can I set needed locale to XDocReport during conversion so the result could be changed to other currencies correctly?
P.S. I cannot control the template itself - so please do not tell me to add <#setting locale="${bean.locale}"> or something else to the template itself. The only place I can change is the code. Thanks in advance.
P.P.S. I need to render many templates per request and need to set locale per each template.
I have never used XDocReport, but maybe this will work: https://github.com/opensagres/xdocreport/wiki/FreemarkerTemplate "How to configure Freemarker?"
Quotation from there:
To configure Freemarker with XDocReport you must get the Configuration instance. To do > that you must
create a class (ex :
fr.opensagres.xdocreport.MyFreemarkerConfiguration) which implements
fr.opensagres.xdocreport.document.discovery.ITemplateEngineInitializerDiscovery.
register with SPI this class by creating the file
META-INF/services/fr.opensagres.xdocreport.document.discovery.ITemplateEngineInitializerDiscovery
with the name of you class :
fr.opensagres.xdocreport.MyFreemarkerConfiguration This file should be
in your classpath (you can for instance host it in the
src/META-INF/services/ of your project).
So you will need a class like this:
public class MyFreemarkerConfiguration implements ITemplateEngineInitializerDiscovery {
[...]
public void initialize(ITemplateEngine templateEngine) {
if (TemplateEngineKind.Freemarker.name().equals( templateEngine.getKind())) {
Configuration cfg = ((FreemarkerTemplateEngine) templateEngine).getFreemarkerConfiguration();
cfg.setLocale(...);
}
}
}

Zapi API - Getting error Expecting claim 'qsh' to have value

I just try to fetch general information from zapi api, but getting error
Expecting claim 'qsh' to have value '7f0d00c2c77e4af27f336c87906459429d1074bd6eaabb81249e1042d4b84374' but instead it has the value '1c9e9df281a969f497d78c7636abd8a20b33531a960e5bd92da0c725e9175de9'
API LINK : https://prod-api.zephyr4jiracloud.com/connect/public/rest/api/1.0/config/generalinformation
can anyone help me please.
The query string parameters must be sorted in alphabetical order, this will resolve the issue.
Please see this link for reference:
https://developer.atlassian.com/cloud/bitbucket/query-string-hash/
I can definitely help you with this. You need to generate the JWT token in the right way.
package com.thed.zephyr.cloud.rest.client.impl;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.thed.zephyr.cloud.rest.ZFJCloudRestClient;
import com.thed.zephyr.cloud.rest.client.JwtGenerator;
public class JWTGenerator {
public static void main(String[] args) throws URISyntaxException, IllegalStateException, IOException {
String zephyrBaseUrl = "https://prod-api.zephyr4jiracloud.com/connect";
String accessKey = "TYPE YOUR ACCESS KEY-GET IT FROM ZEPHYR";
String secretKey = "TYPE YOUR SECRET KEY-GET IT FROM ZEPHYR";
String userName = "TYPE YOUR USER - GET IT FROM ZEPHYR/JIRA";
ZFJCloudRestClient client = ZFJCloudRestClient.restBuilder(zephyrBaseUrl, accessKey, secretKey, userName).build();
JwtGenerator jwtGenerator = client.getJwtGenerator();
String createCycleUri = zephyrBaseUrl + "/public/rest/api/1.0/cycles/search?versionId=<TYPE YOUR VERSION ID HERE>&projectId=<TYPE YOUR PROJECT ID HERE>";
URI uri = new URI(createCycleUri);
int expirationInSec = 360;
String jwt = jwtGenerator.generateJWT("GET", uri, expirationInSec);
//String jwt = jwtGenerator.generateJWT("PUT", uri, expirationInSec);
//String jwt = jwtGenerator.generateJWT("POST", uri, expirationInSec);
System.out.println("FINAL API : " +uri.toString());
System.out.println("JWT Token : " +jwt);
}
}
Also clone this repository: https://github.com/zephyrdeveloper/zfjcloud-rest-api which will give you all methods where respective encodings are there. You can build a Maven project to have these dependencies directly imported.
*I also spent multiple days to figure it out, so be patient and it's only the time till you generate right JWT.

Dynamic Method Invocation and JAXBElement Type on CXF

I wrote the small application below to list all the methods and of a soap service using Apache CXF library. This application lists all the methods of the service, but as it is seen on the output when you run this application, input parameters and return types of the service methods are JAXBElement for the complex types. I want cxf not to generate JAXBElement, instead I want the complex types in their original classes generated on runtime. As it is said on http://s141.codeinspot.com/q/1455881 , it can be done by setting generateElementProperty property's value to false for wsdl2java utility of cxf library, but I couldn't find the same parameter for dynamic method invocation with cxf library. I want to obtain input parameters and return types in their original types.
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import org.apache.cxf.binding.Binding;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingMessageInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceModelUtil;
public class Main {
public static void main(String[] args) {
URL wsdlURL = null;
try {
wsdlURL = new URL("http://path_to_wsdl?wsdl");
} catch (MalformedURLException e) {
e.printStackTrace();
}
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsdlURL, classLoader);
Binding binding = client.getEndpoint().getBinding();
BindingInfo bindingInfo = binding.getBindingInfo();
Collection<BindingOperationInfo> operations = bindingInfo.getOperations();
for(BindingOperationInfo boi:operations){
OperationInfo oi = boi.getOperationInfo();
BindingMessageInfo inputMessageInfo = boi.getInput();
List<MessagePartInfo> parts = inputMessageInfo.getMessageParts();
System.out.println("function name: "+oi.getName().getLocalPart());
List<String> inputParams = ServiceModelUtil.getOperationInputPartNames(oi);
System.out.println("input parameters: "+inputParams);
for(MessagePartInfo partInfo:parts){
Class<?> partClass = partInfo.getTypeClass(); //here we have input parameter object on each iteration
Method[] methods = partClass.getMethods();
for(Method method:methods){
System.out.println("method: "+method);
Class<?>[] paramTypes = method.getParameterTypes();
for(Class paramType:paramTypes){
System.out.println("param: "+paramType.getCanonicalName());
}
Class returnType = method.getReturnType();
System.out.println("returns: "+returnType.getCanonicalName());
}
System.out.println("partclass: "+partClass.getCanonicalName());
}
}
System.out.println("binding: " + binding);
}
}
Create a binding file that looks like:
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateElementProperty="false">
<xjc:simple />
</jaxb:globalBindings>
</jaxb:bindings>
and pass that into the JaxWsDynamicClientFactory via the createClient method that takes the List of binding files.