Home > Articles

This chapter is from the book

This chapter is from the book

Using Kotlin Code from Java

The other way around, Kotlin code can also be called from Java. The best way to understand how to access certain elements, such as extension functions or top-level declarations, is to explore how Kotlin translates to Java bytecode. An additional benefit of this is that you get more insights into the inner workings of Kotlin.

Accessing Properties

Before diving into the details, remember that when I say “field,” I’m usually referring to Java (unless I’m explicitly referring to Kotlin’s backing fields). Contrarily, when talking about “properties,” I’m referring to Kotlin because they don’t directly exist in Java.

As you know, you don’t need to implement property getters and setters manually in Kotlin. They’re created automatically and can be accessed from Java as you would expect, as shown in Listing 5.10.

Listing 5.10 Calling Getters and Setters

// Kotlin
class KotlinClass {
  val fixed: String = "base.KotlinClass"
  var mutable: Boolean = false
}

// Java
KotlinClass kotlinClass = new KotlinClass();
String s = kotlinClass.getFixed();     // Uses getter of ‘val’
kotlinClass.setMutable(true);           // Uses setter of ‘var’
boolean b = kotlinClass.getMutable();  // Uses getter of ‘var’

Notice that Boolean getters also use the prefix get by default instead of is or has. However, if the property name itself starts with is, the property name is used as the getter name—and not just for Boolean expressions; this is irrespective of the property type. Thus, calling the Boolean property isMutable instead would result in the getter of the same name isMutable. Again, there’s currently no such mechanism for properties starting with has but you can always define your own JVM name by annotating the getter or setter with @JvmName, as in Listing 5.11.

Listing 5.11 Custom Method Name Using @JvmName

// Kotlin
class KotlinClass {
  var mutable: Boolean = false
    @JvmName("isMutable") get         // Specifies custom getter name for Java bytecode
}

// Java
boolean b = kotlinClass.isMutable();  // Now getter is accessible as ‘isMutable’

Exposing Properties as Fields

As you’ve learned, properties are compiled to a private field with getter and setter by default (this is also the case for file-level properties). However, you can use @JvmField to expose a property directly as a field in Java, meaning the field inherits the visibility of the Kotlin property and no getter or setter is generated. Listing 5.12 demonstrates the difference.

Listing 5.12 Exposing a Property as a Field using @JvmField

// Kotlin
val prop = "Default: private field + getter/setter" // Here no setter because read-only

@JvmField
val exposed = "Exposed as a field in Java"          // No getter or setter generated

// Decompiled Java code (surrounding class omitted)
@NotNull private static final String prop = "Default: private field + getter/setter";
@NotNull public static final String getProp() { return prop; }

@NotNull public static final String exposed = "Exposed as a field in Java";

As you can see, the property annotated with @JvmField is compiled to a public field that can be accessed directly in Java. This works the exact same way for properties inside a class; by default, they are also accessible via getters and setters but can be exposed as fields.

Note that there are several restrictions for using the @JvmField annotation, and it’s a good exercise to think about why these restrictions exist.

  • The annotated property must have a backing field. Otherwise, there would be no field to expose in the Java bytecode.

  • The property cannot be private because that makes the annotation superfluous. For private properties, no getters or setters are generated anyway because there would be no value to them.

  • The property cannot have the const modifier. Such a property becomes a static final field with the property’s visibility anyway, so @JvmField would have no effect.

  • It cannot have an open or override modifier. This way, field visibilities and existence of getters and setters is consistent between superclass and subclasses. Otherwise, you could accidentally hide the superclass field in Java with a field that has a more restrictive visibility. This can lead to unexpected behavior and is a bad practice.

  • A lateinit property is always exposed so that it can be initialized from anywhere it’s accessible, without assumptions about how it’s initialized. This is useful when an external framework initializes the property. @JvmField would be superfluous here as well.

  • It cannot be a delegated property. Delegation only works with getters and setters that can be routed to the delegate’s getValue and setValue methods, respectively.

Using File-Level Declarations

In Kotlin, you can declare properties and functions on the file level. Java doesn’t support this, so these are compiled to a class that contains the properties and functions. Let’s say you have a Kotlin file sampleName.kt in a package com.example as in Listing 5.13.

Listing 5.13 File-Level Declarations in Kotlin

// sampleName.kt
package com.example

class FileLevelClass                        // Generates class FileLevelClass
object FileLevelObject                      // Generates FileLevelObject as Singleton
fun fileLevelFunction() {}                  // Goes into generated class SampleNameKt
val fileLevelVariable = "Usable from Java"  // Goes into generated class SampleNameKt

Note that classes and objects are also file-level declarations but are simply compiled to a corresponding Java class as you would expect (classes generated for objects implement the singleton pattern). The concepts of file-level properties and functions cannot be mapped to Java directly. So for the code in Listing 5.13, the compiler generates not only the classes com.example.FileLevelClass and com.example.FileLevelObject but also a class com.example.SampleNameKt with a static field for the file-level property and a static method for the file-level function. The fields are private with a public static getter (and setter).

You can explore all classes in the decompiled Java code. The static members can be called from Java as usual after importing SampleNameKt or statically importing the members.

You can also give a shorter and more meaningful name to the generated class than the one based on the file name. This is done in Kotlin using @file:JvmName("<YOUR_NAME>") to annotate the entire file, as shown in Listing 5.14.

Listing 5.14 Using @JvmName on File Level

// sampleName.kt
@file:JvmName("MyUtils")  // Must be the first statement in the file 
// ...

This way, the name of the generated class is MyUtils. You can even compile multiple Kotlin files into a single Java class by adding @file:JvmMultifileClass and @file:JvmName with the same name given to all of them. Be aware that using this increases the chance of name clashes and should only be used if all incorporated file-level declarations are closely related; this is questionable because they come from separate Kotlin files, so use this judiciously.

There are several other annotations that allow you to adjust some parameters of how your Kotlin code is mapped to Java. All of these consistently use the @Jvm prefix, and most will be discussed in this chapter.

Calling Extensions

Extension functions and properties are typically declared on the file level and can then be called as a method on the generated class like other top-level declarations. In contrast to Kotlin, they cannot be called on the extension receiver type directly because there is no such feature in Java. Listing 5.15 provides a brief example.

Listing 5.15 Calling Top-Level Extensions

// Kotlin
@file:JvmName("Notifications")

fun Context.toast(message: String) {  // Top-level function => becomes static method
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

// Within a Java Activity (Android)
Notifications.toast(this, "Quick info...");

Here, you define an extension function that facilitates showing toast messages on Android and use @JvmName to provide a more descriptive name for the generated class. From Kotlin, you could simply call this extension method as toast("Quick info…") from inside an activity because every activity is itself a context, and Context is the receiver type for this extension. With a static import, you can achieve a similar syntax in Java but the Context must still be passed in as the first argument.

Similarly, you can declare extensions inside a type declaration such as a class or object. These can be called from Java via an instance of that encompassing type. To highlight the difference, Listing 5.16 defines a similar extension but this time inside a Notifier class.

Listing 5.16 Calling Class-Local Extensions

// Kotlin
class Notifier {
    fun Context.longToast(message: String) {  // Becomes member method
        Toast.makeText(this, message, Toast.LENGTH_LONG).show()
    }
}

// Calling from a Kotlin Android activity
with(Notifier()) { longToast("Important notification...") }
Notifier().apply { longToast("Important notification...") }

// Calling from a Java Android Activity
Notifier notifier = new Notifier();
notifier.longToast(this, "Important notification...");  // ‘this’ is the Context arg

To call a class-local extension from outside its containing class, you need an instance of the containing class, irrespective of whether you want to call it from Kotlin or Java. From Java, you can call it as a static method on the instance and must again pass in the context. From Kotlin, you have to get access to the class scope, which you can do via with or apply. Recall that, inside the lambda expression, you can then write code as if you were inside the Notifier class. In particular, you can call longToast.

Accessing Static Members

Several of Kotlin’s language elements compile down to static fields or methods. These can be called directly on their containing class as usual.

Static Fields

Although there’s no static keyword in Kotlin, there are several language elements in Kotlin that will generate static fields in the Java bytecode and can thus be called as such from Java. Apart from the examples already seen (top-level declarations and extensions), static fields may be generated from:

  • Properties in object declarations

  • Properties in companion objects

  • Constant properties

All these are shown in Listing 5.17.

Listing 5.17 Generating Static Fields on the JVM

// Kotlin
const val CONSTANT = 360

object Cache { val obj = "Expensive object here..." }

class Car {
  companion object Factory { val defaultCar = Car() }
}

// Decompiled Java code (simplified)
public final class StaticFieldsKt {
  public static final int CONSTANT = 360;
}

public final class Cache {  // Simplified
  private static final String obj = "Expensive object here..."; // private static field
  public final String getObj() { return obj; }                  // with getter
}

public final class Car {    // Simplified
  private static final Car defaultCar = new Car();              // Static field
  public static final class Factory {
    public final Car getDefaultCar() { return Car.defaultCar; } // Nonstatic method
  }
}

Properties from object declarations and companion objects produce private fields with getters and setters. For object declarations, these are inside the Java class that corresponds to the object, such as Cache. For companion objects, the field itself lives inside the containing class while the getter and setter stay inside the nested class. Static members are accessed as usual from Java, for instance as Cache.INSTANCE.getObj() or Car.Factory.getDefaultCar().

The generated static fields are private by default (except when using const) but they can again be exposed using @JvmField. Alternately, you could use lateinit or const; as you learned, these also expose the field. However, it’s not their main purpose but rather a side effect. Note that, using @JvmField, the static field gets the visibility of the property itself whereas using lateinit, it gets the visibility of the setter.

Static Methods

While top-level functions become static methods in the Java bytecode by default, methods declared in named and companion objects are not static by default. You can change this using the @JvmStatic annotation as shown in Listing 5.18.

Listing 5.18 Using @JvmStatic to Generate Static Methods

// Kotlin
object Cache {
  @JvmStatic fun cache(key: String, obj: Any) { … }  // Becomes a static member
}

class Car {
  companion object Factory {
    @JvmStatic fun produceCar() { … }                  // Now becomes static as well
  }
}

// Inside a Java method
Cache.cache("supercar", new Car());     // Static member is callable directly on class
Cache.INSTANCE.cache("car", new Car());  // Bad practice

Car.produceCar();                        // Static
Car.Factory.produceCar();                // Also possible 
(new Car()).produceCar();                // Bad practice

In named objects (object declarations), using @JvmStatic allows you to call the method directly on the class, as you’re used to for static methods. Also, it’s unfortunately possible to call static methods on instances as well but you should avoid this because it can lead to confusing code and adds no value. Nonstatic methods of named objects can only be called on instances, as usual.

In companion objects, using @JvmStatic allows you to call the method directly on the enclosing class; here, Car. It can still be called explicitly on the nested companion object as well. Nonstatic methods can only be called as instance methods on the companion object; here, Car.Factory. Again, the static method on an instance should be avoided.

You can also use @JvmStatic on named and companion object properties to make their accessors static. But you cannot use @JvmStatic outside of named and companion objects.

Generating Method Overloads

Method overloading can often be avoided in Kotlin using default parameter values, saving many lines of code. When compiling to Java, you can decide whether overloaded methods should be generated to enable optional parameters in Java to some extent, as in Listing 5.19.

Listing 5.19 Generating Overloads with @JvmOverloads

// Kotlin
@JvmOverloads  // Triggers generation of overloaded methods in Java bytecode
fun <T> Array<T>.join(delimiter: String = ", ",
                      prefix: String = "",
                      suffix: String = ""): String {
  return this.joinToString(delimiter, prefix, suffix)
}

// Java
String[] languages = new String[] {"Kotlin", "Scala", "Java", "Groovy"};

// Without @JvmOverloads: you must pass in all parameters
ArrayUtils.join(languages, ";", "{", "}");    // Assumes @file:JvmName("ArrayUtils")

// With @JvmOverloads: overloaded methods
ArrayUtils.join(languages);                   // Skips all optional parameters
ArrayUtils.join(languages, "; ");             // Skips prefix and suffix
ArrayUtils.join(languages, "; ", "Array: ");  // Skips suffix
ArrayUtils.join(languages, "; ", "[", "]");   // Passes in all possible arguments

Using @JvmOverloads, the compiler generates one additional overloaded method for each parameter with default value. This results in a series of methods where each has one fewer parameters, the optional one. Naturally, parameters without default value are never omitted. This increases flexibility when calling the method from Java but still doesn’t allow as many combinations as Kotlin because the order of parameters is fixed and you cannot use named parameters. For instance, you cannot pass in a suffix without passing in a prefix.

Note that you can also use @JvmOverloads on constructors to generate overloads. Also, if all parameters of a constructor have a default value, a parameterless constructor is generated anyway, even without the annotation. This is done to support frameworks that rely on parameterless constructors.

Using Sealed and Data Classes

Both sealed classes and data classes translate to normal classes in Java and can be used as such. Of course, Java does not treat sealed classes specially, so they cannot be used with Java’s switch as they can with Kotlin’s when. For instance, you must use instanceof checks to determine the specific type of an object of the parent sealed class, as shown in Listing 5.20.

Listing 5.20 Working with Sealed Classes

// Kotlin
sealed class Component
data class Composite(val children: List<Component>) : Component()
data class Leaf(val value: Int): Component()

// Java
Component comp = new Composite(asList(new Leaf(1), new Composite(…)));

if (comp instanceof Composite) {       // Cannot use ‘switch’, must use ‘if’
  out.println("It's a Composite");  // No smart-casts
} else if (comp instanceof Leaf) {      // No exhaustiveness inferred
  out.println("It's a Leaf");
}

The sealed class becomes an abstract class, making it impossible to instantiate an object of it. Its child classes can be used as normal classes but carry no special semantics in Java because there is no concept for sealed classes.

Data classes can be used intuitively from Java, but there are two restrictions to keep in mind. First, Java does not support destructuring declarations so that the componentN functions are unnecessary. Second, there are no overloads generated for the copy method so that it has no benefit compared to using the constructor. This is because generating all possible overloads would introduce an exponential number of methods (with respect to the number of parameters). Also, generating only some overloads as is the case for @JvmOverloads, there is no guarantee that this would generate a useful subset of overloads. Hence, no overloads are generated at all for copy. All of this is illustrated in Listing 5.21.

Listing 5.21 Working with Data Classes

// Kotlin
data class Person(val name: String = "", val alive: Boolean = true)

// Java
Person p1 = new Person("Peter", true);
Person p2 = new Person("Marie Curie", false);
Person p3 = p2.copy("Marie Curie", false);  // No advantage over constructor

String name = p1.getName();  // componentN() methods superfluous
out.println(p1);             // Calls toString()
p2.equals(p3);               // true

Visibilities

The available visibilities don’t map exactly between Kotlin and Java, plus you have top-level declarations in Kotlin. So let’s explore how visibilities are mapped to Java. First, some visibilities can be mapped trivially.

  • Private members remain private.

  • Protected members remain protected.

  • Public language elements remain public, whether top-level or member.

Other visibilities cannot be mapped directly but are rather compiled to the closest match:

  • Private top-level declarations also remain private. However, to allow calls to them from the same Kotlin file (which may be a different class in Java), synthetic methods are generated on the JVM. Such methods cannot be called directly but are generated to forward calls that would not be possible otherwise.

  • All of Kotlin’s internal declarations become public because package-private would be too restrictive. Those declared inside a class go through name mangling to avoid accidental calls from Java. For instance, an internal method C.foo will appear as c.foo$production_sources_for_module_yourmodulename() in the bytecode, but you’re not able to actually call them as such. You can use @JvmName to change the name in the Java bytecode if you want to be able to call internal members from Java.

This explains how each visibility maps to Java for both top-level declarations and members.

Getting a KClass

KClass is Kotlin’s representation of classes and provides reflection capabilities. In case you have a Kotlin function accepting a KClass as a parameter and need to call it from Java, you can use the predefined class kotlin.jvm.JvmClassMappingKt as in Listing 5.22. From Kotlin, you can access both KClass and Class more easily.

Listing 5.22 Getting KClass and Class References

// Java
import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KClass;

KClass<A> clazz = JvmClassMappingKt.getKotlinClass(A.class);

// Kotlin
import kotlin.reflect.KClass

private val kclass: KClass<A> = A::class
private val jclass: Class<A> = A::class.java

Handling Signature Clashes

With Kotlin, you may declare methods that have the same JVM signature. This mostly happens due to type erasure of generics types, meaning that type parameter information is not available at runtime on the JVM. Thus, at runtime, Kotlin (like Java) only knows that List<A> and List<B> have type List. Listing 5.23 demonstrates the situation.

Listing 5.23 JVM Name Clash

fun List<Customer>.validate() {}    // JVM signature: validate(java.util.List)
fun List<CreditCard>.validate() {}  // JVM signature: validate(java.util.List)

Here, you wouldn’t be able to call these methods from Java because there’s no way to differentiate between the two at runtime. In other words, they end up with the same bytecode signature. As you may expect, this is easily resolved using @JvmName, as in Listing 5.24.

Listing 5.24 Resolving JVM Name Clashes

fun List<Customer>.validate() { … }

@JvmName("validateCC")  // Resolves the name clash
fun List<CreditCard>.validate() { … }

// Both can be called as validate() from Kotlin (because dispatched at compile-time)
val customers = listOf(Customer())
val ccs       = listOf(CreditCard())
customers.validate()
ccs.validate()

From Java, the methods are available as two static methods, FileNameKt.validate and FileNameKt.validateCC. From Kotlin, you can access both as validate because the compiler dispatches that to the appropriate method internally (at compile time, all necessary type information for this is available).

Using Inline Functions

You can call inline functions from Java just like any other function, but of course they are not actually inlined—there is no such feature in Java. Listing 5.25 demonstrates inlining when used from Kotlin. Be aware that inline functions with reified type parameters are not callable from Java at all because it doesn’t support inlining, and reification without inlining doesn’t work. Thus, you cannot use reified type parameters in methods that should be usable from Java.

Listing 5.25 Calling Inline Functions (from Kotlin)

// Kotlin
inline fun require(predicate: Boolean, message: () -> String) {
  if (!predicate) println(message())
}

fun main(args: Array<String>) {  // Listing uses main function to show decompiled code
  require(someCondition()) { "someCondition must be true" }
}

// Decompiled Java Code (of main function)
public static final void main(@NotNull String[] args) {
  Intrinsics.checkParameterIsNotNull(args, "args");  // Always generated by Kotlin
  boolean predicate$iv = someCondition();
  if (!predicate$iv) {                               // Inlined function call
    String var2 = "someCondition must be true";
    System.out.println(var2);
  }
}

As you can see, the if statement and its body are inlined into the main method and there is no actual call to the require method anymore. Without the inline keyword, or when calling the method from Java, there would be a call to require instead.

Exception Handling

Because there are no checked exceptions in Kotlin, you can call all Kotlin methods from Java without handling exceptions. This is because exceptions are then not declared in the bytecode (there are no throws clauses). To allow exception handling in Java, you can use the @Throws annotation as shown in Listing 5.26.

Listing 5.26 Generating Throws Clauses

// Kotlin
import java.io.*

@Throws(FileNotFoundException::class)  // Generates throws clause in bytecode
fun readInput() = File("input.csv").readText()

// Java
import java.io.FileNotFoundException;
// …
try {                     // Must handle exception
  CsvUtils.readInput();  // Assumes @file:JvmName("CsvUtils")
} catch (FileNotFoundException e) {
  // Handle non-existing file...
}

Without the @Throws annotation, you could call the readInput method from both Kotlin and Java without handling exceptions. With the annotation, you’re free to handle exceptions when calling it from Kotlin, and you must handle all checked exceptions when calling it from Java.

Looking at the decompiled Java code, you can see that all the annotation does is to add a throws FileNotFoundException to the method signature, as demonstrated in Listing 5.27.

Listing 5.27 Difference in Decompiled Java Code

// Without @Throws
public static final String readInput() { ... }

// With @Throws
public static final String readInput() throws FileNotFoundException { ... }

Using Variant Types

Regarding variant types, there’s a disparity between Kotlin and Java because Java only has use-site variance whereas Kotlin also has declaration-site variance. Thus, Kotlin’s declaration-site variance must be mapped to use-site variance. How is this done? Whenever an out-projected type appears as a parameter or variable type, the wildcard type <? extends T> is automatically generated. Conversely, for in-projected types that appear as a parameter, <? super T> is generated. This lets you use the type’s variance in Java. Consider Listing 5.28 as an example.

Listing 5.28 Mapping Declaration-Site Variance to Use Site

// Kotlin
class Stack<out E>(vararg items: E) { … }
fun consumeStack(stack: Stack<Number>) { … }

// Java: you can use the covariance of Stack
consumeStack(new Stack<Number>(4, 8, 15, 16, 23, 42));
consumeStack(new Stack<Integer>(4, 8, 15, 16, 23, 42));

The Java signature for the consumeStack method is void consumeStack(Stack<? extends Number> stack) so that you can call it with a Stack<Number> as well as a Stack<Integer>. You cannot see this signature in the decompiled Java code due to type erasure, but looking at the Kotlin bytecode directly, you can find a comment stating declaration: void consumeStack(Stack<? extends java.lang.Number>). So you’re still able to use the bytecode tool to see what’s happening internally.

The generation of wildcard types only happens when in- or out-projected types are used as parameters. For return types, no such wildcards are generated because this would go against Java coding standards. Still, you can intercept the generation process here as well. To generate wildcards where they normally wouldn’t, you can use @JvmWildcard as in Listing 5.29. To suppress wildcards, you can use @JvmSuppressWildcards, also shown in Listing 5.29.

Listing 5.29 Adjusting Wildcard Generation

// Kotlin
fun consumeStack(stack: Stack<@JvmSuppressWildcards Number>) { … } // No more wildcards

// Normally no wildcards are generated for return types, unless you use @JvmWildcard
fun produceStack(): Stack<@JvmWildcard Number> {
  return Stack(4, 8, 15, 16, 23, 42)
}

// Java
consumeStack(new Stack<Number>(4, 8, 15, 16, 23, 42));   // Matches exactly
consumeStack(new Stack<Integer>(4, 8, 15, 16, 23, 42));  // Error: No longer allowed

Stack<Number> stack = produceStack();           // Error: No longer allowed
Stack<? extends Number> stack = produceStack();  // Inconvenient, thus bad practice

Note that you can also annotate methods or even whole classes with these to control wildcard generation. However, most of the time you’ll be able to call Kotlin methods from Java just fine without intercepting the generation process because declaration-site variance is mapped sensibly by default.

The Nothing Type

Lastly, there’s no counterpart to Kotlin’s Nothing type in Java because even java.lang.Void accepts null as a value. Because it’s still the closest representation of Nothing that’s available in Java, Nothing return types and parameters are mapped to Void. As shown in Listing 5.30, this doesn’t result in the exact same behavior.

Listing 5.30 Using the Nothing Type

// Kotlin
fun fail(message: String): Nothing {          // Indicates non-terminating function
  throw AssertionError(message)
}

fun takeNothing(perpetualMotion: Nothing) {}  // Impossible to call from Kotlin

// Java
NothingKt.takeNothing(null); // Possible in Java (but with warning due to @NonNull)
NothingKt.fail("Cannot pass null to non-null variable");    // Cannot terminate
System.out.println("Never reached but Java doesn't know");  // Dead code

You can actually call takeNothing from Java, an action not possible from Kotlin. However, you’ll at least receive a warning because the signature is void takeNothing(@NonNull Void perpetualMotion). Since null is the only valid value for Void, that’s really the closest representation of Nothing currently available in Java. Similarly, the return type of fail becomes Void so that Java cannot infer unreachable code like Kotlin.

Lastly, using Nothing as a generic type argument generates a raw type in Java to at least provoke unchecked call warnings. For instance, List<Nothing> becomes a raw List in Java.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020