Importing MPP library using MavenLocal to another project containing an mpp library. ERROR: No matching variant of was found - mpp

We are having trouble importing an MPP library (A) into another MPP module from a different project (B). We have published library (A) to the local maven repository and we are able to import library (A) from modules in the project (B) that are not multi-platform however when we try to import library (A) from a module in project (B) that is multi-platform it is not recognized. The library that we are trying to import into (B) is named "com.XXX:streaming-shared-android:0.0.3".
Error message:
Execution failed for task ':mpp:es-data:compileKotlinAndroid'.
> Error while evaluating property 'filteredArgumentsMap' of task ':mpp:es-data:compileKotlinAndroid'
> Could not resolve all files for configuration ':mpp:es-data:androidCompileClasspath'.
> Could not resolve com.englishscore:es-core-domain:0.0.3.
Required by:
project :mpp:es-data
> No matching variant of com.englishscore:es-core-domain:0.0.3 was found. The consumer was configured to find an API of a library, preferably optimized for standard JVMs, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but:
- Variant 'debugApiElements-published' capability com.englishscore:es-core-domain:0.0.3 declares an API of a library:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'debugRuntimeElements-published' capability com.englishscore:es-core-domain:0.0.3 declares a runtime of a library:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'iOSApiElements-published' capability com.englishscore:es-core-domain:0.0.3 declares a library:
- Incompatible because this component declares a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native' and the consumer needed an API of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'iOSMetadataElements-published' capability com.englishscore:es-core-domain:0.0.3 declares a library:
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native' and the consumer needed an API of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'metadataApiElements' capability com.englishscore:es-core-domain:0.0.3 declares a library:
- Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'common' and the consumer needed an API of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'releaseApiElements-published' capability com.englishscore:es-core-domain:0.0.3 declares an API of a library:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
- Variant 'releaseRuntimeElements-published' capability com.englishscore:es-core-domain:0.0.3 declares a runtime of a library:
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm'
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
Gradle file of project A
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
// Define Kotlin version
group = "com.englishscore"
version = "0.0.3"
plugins {
// Make this a multiplatform module
kotlin("multiplatform")
// Kotlin serialization consists of a compiler plugin, that generates visitor code for serializable classes
kotlin("plugin.serialization") version "1.6.10"
// Add support for the Android module in the multiplatform library. If you don't add this, you won't have access to
// android features in the platform side of the library. It will be basic JVM
id("com.android.library")
// Allows to export the iOS module as a swift package WIP
// id("com.chromaticnoise.multiplatform-swiftpackage") version ("2.0.3")
// Allows to publish the module
`maven-publish`
// Allows you to export the iOS module as standalone cocoapods dependency
kotlin("native.cocoapods")
}
// Sources for dependecies
repositories {
mavenCentral()
google()
}
kotlin {
// Library version
val ktorVersion: String by project
val coroutinesVersion: String by project
val koinVersion: String by project
/* Targets configuration omitted.
* To find out how to configure the targets, please follow the link:
* https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets */
// val iosTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = when {
// System.getenv("SDK_NAME")?.startsWith("iphoneos") == true -> ::iosArm64
// System.getenv("NATIVE_ARCH")?.startsWith("arm") == true -> ::iosSimulatorArm64 // available to KT 1.5.30
// else -> ::iosX64
// }
iosX64("iOS")
// Enables Android as a target
android()
// Enables JS as a target
// js(IR) {
// moduleName = project.name
// browser()
// binaries.library()
// }
// Pod config for exporting the library
cocoapods {
framework {
// Mandatory properties
// Configure fields required by CocoaPods.
summary = "Base module for EnglishScore business logic"
homepage = "LINK REQUIRED"
// Framework name configuration. Use this property instead of deprecated 'frameworkName'
baseName = "es_core_domain"
// Optional properties
// (Optional) Dynamic framework support
isStatic = false
// (Optional) Dependency export
// export(project(":anotherKMMModule"))
transitiveExport = true
// (Optional) Bitcode embedding
embedBitcode(org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode.BITCODE)
}
// Maps custom Xcode configuration to NativeBuildType
xcodeConfigurationToNativeBuildType["CUSTOM_DEBUG"] = org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.DEBUG
xcodeConfigurationToNativeBuildType["CUSTOM_RELEASE"] = org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType.RELEASE
}
// Defining the sources for the project. Mainly for providing platform specific dependencies
sourceSets {
all {
// Removes all compilation warnings for #OptIn annotation
languageSettings.optIn("kotlin.RequiresOptIn")
}
val commonMain by getting {
dependencies {
api(kotlin("stdlib-common"))
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
api("io.insert-koin:koin-core:$koinVersion")
}
}
val androidMain by getting {
dependencies {
}
}
val iOSMain by getting {
dependencies {
}
}
// val jsMain by getting {
// dependencies {
// implementation(kotlin("stdlib-js"))
// implementation("io.ktor:ktor-client-logging-js:$ktorVersion")
// implementation("io.ktor:ktor-client-js:$ktorVersion")
// implementation("io.ktor:ktor-client-core-js:$ktorVersion")
// implementation("io.ktor:ktor-serialization-kotlinx-json-js:$ktorVersion")
// implementation("io.ktor:ktor-serialization-kotlinx-js:$ktorVersion")
// }
// }
}
android {
publishLibraryVariants("release", "debug")
}
}
// Android library configuration
android {
val androidCompileSDKAPILevel: String by project
compileSdk = Integer.parseInt(androidCompileSDKAPILevel)
sourceSets["main"].manifest.srcFile("src/androidMain/kotlin/AndroidManifest.xml")
}
//multiplatformSwiftPackage {
// packageName("streaming-spike")
// swiftToolsVersion("5.3")
// targetPlatforms {
// iOS { v("13") }
// }
//}
Gradle file of project B
ext {
kodein_version = "6.4.1"
slf_logger_version = "1.7.30"
}
buildscript {
repositories {
mavenCentral()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
}
apply plugin: "kotlin-multiplatform"
apply plugin: "kotlinx-serialization"
apply plugin: "maven-publish"
kotlin {
jvm("android") {
mavenPublication {
artifactId = 'data-android'
}
}
js("web") {
browser() {
configure(compilations.main) {
tasks.getByName(compileKotlinTaskName).kotlinOptions {
version = js_lib_version
metaInfo = true
sourceMap = true
moduleKind = "commonjs"
// outputFile = "${rootProject.buildDir}/npm/${project.name}/${project.name}.js"
}
}
}
mavenPublication {
artifactId = 'data-web'
}
}
sourceSets {
all {
dependencies {
api project(":mpp:es-domain")
}
}
androidMain {
dependencies {
implementation "com.XXX:streaming-shared-android:0.0.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_core_version"
implementation "io.ktor:ktor-client-android:$ktor_version"
implementation "io.ktor:ktor-client-json-jvm:$ktor_version"
implementation "io.ktor:ktor-client-logging-jvm:$ktor_version"
implementation "io.ktor:ktor-client-serialization-jvm:$ktor_version"
implementation "org.slf4j:slf4j-simple:$slf_logger_version"
}
}
commonMain {
dependencies {
implementation "com.XXX:streaming-shared:0.0.3
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_core_version")
implementation "org.jetbrains.kotlinx:kotlinx-datetime:$datetime_core_version"
implementation "io.github.aakira:napier:$napier_version"
implementation "io.ktor:ktor-client-core:$ktor_version"
implementation "io.ktor:ktor-client-json:$ktor_version"
implementation "io.ktor:ktor-client-logging:$ktor_version"
implementation "io.ktor:ktor-client-serialization:$ktor_version"
implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"
}
}
webMain {
dependencies {
api "io.ktor:ktor-client-js:$ktor_version"
api "io.ktor:ktor-client-core-js:$ktor_version"
api "io.ktor:ktor-client-json-js:$ktor_version"
api "io.ktor:ktor-client-logging-js:$ktor_version"
api "io.ktor:ktor-client-serialization-js:$ktor_version"
api "org.kodein.di:kodein-di-erased-js:$kodein_version"
}
}
}
}

Related

SQL with Prisma under Electron

My Main goal is to create an Electron App (Windows) that locally stores data in an SQLite Database. And because of type safety I choose to use the Prisma framework instead of other SQLite Frameworks.
I took this Electron Sample Project and now try to include Prisma. Depending on what I try different problems do arrise.
1. PrismaClient is unable to be run in the Browser
I executed npx prisma generate and then try to execute this function via a button:
import { PrismaClient } from '#prisma/client';
onSqlTestAction(): void {
const prisma = new PrismaClient();
const newTestObject = prisma.testTable.create(
{
data: {
value: "TestValue"
}
}
);
}
When executing this in Electron I get this:
core.js:6456 ERROR Error: PrismaClient is unable to be run in the browser.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
at new PrismaClient (index-browser.js:93)
at HomeComponent.onSqlTestAction (home.component.ts:19)
at HomeComponent_Template_button_click_7_listener (template.html:7)
at executeListenerWithErrorHandling (core.js:15281)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15319)
at HTMLButtonElement.<anonymous> (platform-browser.js:568)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28666)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
It somehow seems logical that Prisma cannot run in a browser. But I actually build a native app - with Electron that embeds a Browser. It seems to be a loophole.
2. BREAKING CHANGE: webpack < 5 used to include polyfills
So i found this Question: How to use Prisma with Electron
Seemed to be exactly what I looked for. But the error message is different (Debian binaries were not found).
The solution provided is to generate the prisma artifacts into the src folder instead of node_modules - and this leads to 19 polyfills errors. One for example:
./src/database/generated/index.js:20:11-26 - Error: Module not found: Error: Can't resolve 'path' in '[PATH_TO_MY_PROJECT]\src\database\generated'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
And this repeats with 18 other modules. Since the error message to begin with was different I also doubt that this is the way to go.
I finally figured this out. What I needed to understand was, that all Electron apps consist of 2 parts: The Frontend Webapp (running in embedded Chromium) and a Node backend server. Those 2 parts are called IPC Main and IPC Renderer and they can communicate with each other. And since Prisma can only run on the main process which is the backend I had to send my SQL actions to the Electron backend and execute them there.
My minimal example
In the frontend (I use Angular)
// This refers to the node_modules folder of the Electron Backend, the folder where the main.ts file is located.
// I just use this import so that I can use the prisma generated classes for type safety.
import { TestTable } from '../../../app/node_modules/.prisma/client';
// Button action
onSqlTestAction(): void {
this.electronService.ipcRenderer.invoke("prisma-channel", 'Test input').then((value) => {
const testObject: TestTable = JSON.parse(value);
console.log(testObject);
});
The sample project I used already had this service to provide the IPC Renderer:
#Injectable({
providedIn: 'root'
})
export class ElectronService {
ipcRenderer: typeof ipcRenderer;
webFrame: typeof webFrame;
remote: typeof remote;
childProcess: typeof childProcess;
fs: typeof fs;
get isElectron(): boolean {
return !!(window && window.process && window.process.type);
}
constructor() {
// Conditional imports
if (this.isElectron) {
this.ipcRenderer = window.require('electron').ipcRenderer;
this.webFrame = window.require('electron').webFrame;
this.childProcess = window.require('child_process');
this.fs = window.require('fs');
// If you want to use a NodeJS 3rd party deps in Renderer process (like #electron/remote),
// it must be declared in dependencies of both package.json (in root and app folders)
// If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
this.remote = window.require('#electron/remote');
}
}
And then in the Electron backend I first added "#prisma/client": "^3.0.1" to the package.json (for the Electron backend not the frontend). Then I added to the main.ts this function to handle the requests from the renderer:
// main.ts
ipcMain.handle("prisma-channel", async (event, args) => {
const prisma = new PrismaClient();
await prisma.testTable.create(
{
data: {
value: args
}
}
);
const readValue = await prisma.testTable.findMany();
return JSON.stringify(readValue);
})
This way of simply adding the IPC Main handler in the main.ts file of course is a big code smell but usefull as minimal example. I think I will move on with the achitecture concept presented in this article.

Why do I get "Unresolved reference: platform" when using the firebase-bom dependency with KMM

When I attempt to add the Firebase-bom dependency using the following block in a Kotlin Multiplatform Mobile (KMM) project's shared module, the word platform appears in red error text and the Gradle build fails with "Unresolved reference: platform." How can I resolve this so it builds correctly?
val androidMain by getting {
dependencies {
implementation(platform("com.google.firebase:firebase-bom:28.0.1"))
implementation("com.google.firebase:firebase-analytics-ktx")
}
}
The answer lies in KT-40489.
The platform() function used to import the Firebase Bill of Materials is not available in Kotlin Multiplatform plugin’s KotlinDependencyHandler but only in Gradle’s standard DependencyHandler. It also does not seem that a fix is coming soon. As a result, you need to specify Gradle's handler explicitly.
Here are two workarounds:
val androidMain by getting {
dependencies {
implementation(project.dependencies.platform("..."))
}
}
OR
val androidMain by getting {
dependencies {
"jvmMainImplementation"(platform("...))
}
}

How to release or distribute an application that uses mikro-orm?

In the configuration I have to specify the paths to .js and .ts files defining entities:
MikroORM.init({
...
entitiesDirs: ["build/entities"],
entitiesDirsTs: ["src/entities"],
});
So, when I will go to release or distribute the application. Will I need distribute the typescript code too? or will I need distribute only the cache generated? or will I need distribute both? or... none?
As of MikroORM v2.2
Now you can work with default metadata provider, it will require entity source files only if you do not provide entity or type options in your decorators (you can use entity callback to use reference to entity class instead of using string name in type, handle for refactoring via IDE like webstorm).
Original answer:
You should ship the typescript code too, and let the cache regenerate on the server - cache would be rebuilt anyway as it checks absolute path to cached entity for invalidation.
You could implement your own cache adapter or metadata provider to get around this, if you don't want to ship the typescript code.
This is how you could implement custom metadata provider that simply throws error when the type option is missing:
import { MetadataProvider, Utils } from 'mikro-orm';
import { EntityMetadata } from 'mikro-orm/dist/decorators';
export class SimpleMetadataProvider extends MetadataProvider {
async loadEntityMetadata(meta: EntityMetadata, name: string): Promise<void> {
// init types and column names
Object.values(meta.properties).forEach(prop => {
if (prop.entity) {
prop.type = Utils.className(prop.entity());
} else if (!prop.type) {
throw new Error(`type is missing for ${meta.name}.${prop.name}`)
}
});
}
}
Then provide this class when initializing:
const orm = await MikroORM.init({
// ...
metadataProvider: SimpleMetadataProvider,
});
The value of type should be JS types, like string/number/Date... You can observe your cached metadata to be sure what values should be there.
Also keep in mind that without TS metadata provider, you will need to specify entity type in #ManyToOne decorator too (either via entity callback, or as a string via type).

Severely truncated attribute while compiling JavaFX Undertow Websockets project for Android with jfxmobile-plugin

I am having an issue while compiling my JavaFX project for Android.
The project includes a bunch of libraries, Undertow Websockets is among them. I downloaded all required jars to my lib directory and included them into dependencies / compile files block of build.gradle file.
I was able to solve other issues with jar-files dependencies (mostly DuplicateFileException), but one Undertow library - undertow-core-1.3.14.Final.jar gives me a little bit of a headache.
When I add it to compile file block of gradle.build file ‘gradlew android’ gives me an error message:
What went wrong: Execution failed for task ‘:createMainDexList’.
Exception in thread “main” com.android.dx.cf.iface.ParseException:
severely truncated attribute at
com.android.dx.cf.direct.StdAttributeFactory.throwSeverelyTruncated(StdAttributeFactory.java:736)
at
com.android.dx.cf.direct.StdAttributeFactory.runtimeVisibleParameterAnnotations(StdAttributeFactory.java:661)
at
com.android.dx.cf.direct.StdAttributeFactory.parse0(StdAttributeFactory.java:162)
at
com.android.dx.cf.direct.AttributeFactory.parse(AttributeFactory.java:96)
at
com.android.dx.cf.direct.AttributeListParser.parse(AttributeListParser.java:141)
at
com.android.dx.cf.direct.AttributeListParser.parseIfNecessary(AttributeListParser.java:115)
at
com.android.dx.cf.direct.AttributeListParser.getEndOffset(AttributeListParser.java:96)
at
com.android.dx.cf.direct.MemberListParser.parse(MemberListParser.java:213)
at
com.android.dx.cf.direct.MemberListParser.parseIfNecessary(MemberListParser.java:108)
at
com.android.dx.cf.direct.MethodListParser.getList(MethodListParser.java:54)
at
com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:542)
at
com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
at
com.android.dx.cf.direct.DirectClassFile.parseToEndIfNecessary(DirectClassFile.java:397)
at
com.android.dx.cf.direct.DirectClassFile.getAttributes(DirectClassFile.java:311)
at
com.android.multidex.MainDexListBuilder.hasRuntimeVisibleAnnotation(MainDexListBuilder.java:191)
at
com.android.multidex.MainDexListBuilder.keepAnnotated(MainDexListBuilder.java:167)
at
com.android.multidex.MainDexListBuilder.(MainDexListBuilder.java:121)
at
com.android.multidex.MainDexListBuilder.main(MainDexListBuilder.java:91)
at
com.android.multidex.ClassReferenceListBuilder.main(ClassReferenceListBuilder.java:58)
…while parsing RuntimeVisibleParameterAnnotations attribute at offset 0009c07 > …while parsing attributes[3]
…while parsing methods[1]
…while parsing io/undertow/client/http/HttpResponseParser$$generated.class
Below is my build.gradle file contents:
task wrapper(type: Wrapper) {
gradleVersion = '2.10'
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.7'
}
}
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
}
mainClassName = 'com.simlayserstudio.SimlayserStudio'
jfxmobile {
android {
manifest = 'src/android/AndroidManifest.xml'
// compileSdkVersion = 16 // version 4.2.1
compileSdkVersion = 23 // version 6
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/INDEX.LIST'
exclude 'META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder'
exclude 'META-INF/services/io.undertow.predicate.PredicateBuilder'
exclude 'META-INF/services/io.undertow.server.handlers.builder.HandlerBuilder'
//exclude 'META-INF/services/javax.annotation.processing.Processor'
}
}
ios {
infoPList = file('src/ios/Default-Info.plist')
}
}
dependencies {
compile ('commons-codec:commons-codec:1.10',
'commons-io:commons-io:2.4',
'commons-lang:commons-lang:2.6',
// 'io.undertow:undertow-servlet:1.3.14.Final' // Duplicate zip entry [allclasses.jar:javax/annotation/Generated.class
)
compile files(
'/lib/jboss-logging-3.2.1.Final.jar', //ok wtih exclude 'META-INF/INDEX.LIST'
// '/lib/undertow-core-1.3.14.Final.jar', // ERROR com.android.dx.cf.iface.ParseException: severely truncated attribute
'/lib/undertow-servlet-1.3.14.Final.jar', // ok wtih exclude ExchangeAttributeBuilder, PredicateBuilder, HandlerBuilder
'/lib/undertow-websockets-jsr-1.3.14.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/xnio-api-3.3.4.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/xnio-nio-3.3.4.Final.jar', //ok with exclude 'META-INF/INDEX.LIST'
'/lib/apache-commons.jar', //ok
'/lib/com.thoughtworks.xstream.jar', //ok
'/lib/javax.websocket-api-1.0.jar', //ok
'/lib/log4j-1.2.17.jar', //ok
'/lib/xmlpull-xpp3-1.1.4c.jar', //ok
)
}
Did anybody manage generating apk with Undertow Websockets, or encounter similar issues with 3-rd party libraries?
Any help would be much appreciated.
Thank you!
I've been able to reproduce the same error you've posted, just by using this dependencies and running ./gradlew android:
dependencies {
compile ('io.undertow:undertow-servlet:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
compile ('io.undertow:undertow-core:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
compile ('io.undertow:undertow-websockets-jsr:1.3.19.Final') {
exclude group: 'org.jboss.spec.javax.annotation'
}
}
So in order to find out about the possible issue, I've downloaded the io.undertow` sources from here, added the required dependencies (maybe I'm not using the exact versions):
dependencies {
compile 'org.jboss.logging:jboss-logging-annotations:2.0.1.Final'
compile 'org.jboss.classfilewriter:jboss-classfilewriter:1.0.4.Final'
compile 'org.eclipse.jetty.alpn:alpn-api:1.0.0'
compile 'org.jboss.xnio:xnio-nio:3.3.4.Final'
compile 'org.jboss.xnio:xnio-api:3.3.4.Final'
compile 'org.jboss.logging:jboss-logging:3.2.1.Final'
compile 'org.jboss.spec.javax.websocket:jboss-websocket-api_1.1_spec:1.1.0.Final'
compile 'org.jboss.spec.javax.servlet:jboss-servlet-api_3.1_spec:1.0.0.Final'
}
And to avoid duplicated classes from javax.annotation, I've downloaded the sources of org.jboss.spec.javax.annotation:jboss-annotations-api_1.1_spec from here, and removed these three classes: Generated.java, PostConstruct.java and PreDestroy.java.
I was able to run ./gradlew android successfully, but I haven't tested it.
In case you still have issues building it or later running it on the device, maybe you can consider other alternatives for websockets like the Tyrus project.
This is a project were we have used it successfully.

Using modules in Meteor.js with Typescript

Folks, I'm trying to do something that I thought ought to be simple, but I must be doing something wrong. I'm trying to simply have a clear structure in my meteor application which uses Typescript.
Here are my requirements:
All interfaces are available in both client and server
Some class implementations are only available on the server
I don't want to rely on file load order for my application to work properly
I need my own module to not clash with global objects (such as the Position class for example)
I need to have one monolithic include file for server, one for both client and server and one for client (don't want to have 10s of includes on top of my files)
The setup that I have right now is this
server
server-book.ts
client
shared
collections.ts
definitions
server
include.d.ts (includes all .d.ts files in this folder)
server-book.d.ts (server specific implementation of book)
client
shared
include.d.ts (includes all .d.ts files here)
book.d.ts (book interface definition)
collections.d.ts
In each .d.ts file I have
module MyModule {
interface Bla {}
};
In each .ts file that defines a class I have:
module MyModule {
export class MyBla implements Bla {};
}
All .d.ts files generated for classes are generated by tsc -d.
No .ts files are being included via ///<reference> rather only .d.ts files.
Now, when I run this, I get an error that MyModule is undefined:
/// <reference path="shared/include.d.ts"/>
/// <reference path="server/include.d.ts"/>
Meteor.startup(() => {
var temp = new MyModule.ServerBook();
});
The error occurs right on MyModule.
What am I doing wrong? What should be the proper setup here?
Thanks!
I have dealt with this issue on my blog. I decided to use the evil eval command, since it gave me the easiest possibility of using modules till something more sophisticated appears.
File /lib/foo.ts is position in the subdirectory since it has to be loaded before Bar.
eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module
module Hugo {
export class Foo {
foo():string {
return 'foo'
}
}
}
File /bar.ts
/// <reference path="lib/foo.ts"/>
eval('var Hugo = (this.Hugo || (this.Hugo = {})'); // this will override the automatically emitted var Hugo and assigns it with globally defined Hugo module
module Hugo {
export class Bar extends Foo {
bar () : string {
return 'bar';
}
}
}
File /test.ts
/// <reference path="lib/foo.ts"/>
/// <reference path="bar.ts"/>
var m = new Hugo.Bar();
console.log(m.bar());
console.log(m.foo());
As mentioned here, for classes, the solution is even simpler:
class ExportedClass {
variable : int;
}
this.ExportedClass = ExportedClass;
Definition files should use the declare keyword. You would normally get an error if you didn't use this keyword.
declare module MyModule {
export interface Bla {}
}
And
declare module MyModule {
export class MyBla implements Bla {
}
}
It is also worth checking that the ServerBook class has the export keyword (just like MyBla in your examples).
After lot of trial and errors, here are my findings so far :
Using typescript "module" keyword doesn't get well with Meteor. I think at the moment you cannot use it (or the workarounds are too complicated for me).
However, here is what you can do :
Let say that you have package A where you want to define a class ClassToExport which you want to make public.
class ClassToExport {
getFoo(){
return "foo";
}
}
Please note that you can't write this.ClassToExport = ClassToExport and
api.export('ClassToExport') or else ClassToExport won't be available in the global scope of package A, hence the need for a module/namespace for exporting your class, which we will see next.
Now, for the class to be available for the consumers of your package, you have to create a namespace, which will be the equivalent of the "module" typescript keyword for internal module.
So let's write :
declare var packageA; //so that the compiler doesn't complain about undeclared var
packageA = packageA || {}; //so that this namespace can be reused for the entire package
packageA.ClassToExport = ClassToExport; //the actual export
Now, don't forget to write
api.export('packageA') in the package.js of package A
If you have a package B where you want to use ClassToExport, you write in package B:
var cte = new packageA.ClassToExport();
without forgetting to api.use package A in package B's package.js
If you don't want to write the namespace each time you use the class, you can also write var ClassToExport = packageA.ClassToExport; at the top of your using file.
If you need a global class for you package only, without exporting it, then you can do instead just :
this.ClassToExport = ClassToExport
and again don't write api.export('ClassToExport'), or it won't be available in the package anymore.
This way, i think the features (export/ import) of internal typescript modules are there.
If you are not afraid of gulp build, I have prepared a typescript boilerplate project which allows you to comfortably use typescript from within your app, not depending on packages.
https://github.com/tomitrescak/meteor-boilerplate-typescript
Random idea, what about extend Meteor instead of Window.
Meteor.yournamespace = Meteor.yournamespace || {};
Meteor.yournamespace.myclass = new MyClass();
or
Meteor.yournamespace.MyClass = MyClass();
I think this is less invasive than go directly to the window object IMHO. my two cents.
now you can do Meteor.yournamespace.MyClass :P
--EDIT
Then you could create a meteor-extend.d.ts file and do something like:
/// <reference path="main.d.ts" />
declare module Meteor {
var yournamespace: any;
}
Now you can remove the <any> before Meteor and Typescript will not complaint.

Resources