A Kotlin compiler plugin that removes the `copy` method of data classes.

Overview

NoCopy Compiler Plugin CI Maven Central

A Kotlin compiler plugin that removes the `copy` method from data classes and enables using them as value-based classes.

Usage

Include the gradle plugin in your project and apply @NoCopy to your data class.

@NoCopy

@NoCopy prevents the kotlin compiler from generating the copy method:

@NoCopy
data class User(val name: String, val phoneNumber: String)
User("Ahmed", "+201234567890").copy(phoneNumber = "Happy birthday!") // Unresolved reference: copy

Why? I hear you ask.

The copy method of Kotlin data classes is a known language design problem, normally, you can't remove it, you can't override it, and you can document it.

Why would you want to do that? Well, there are a couple of reasons:

  • copy is a guaranteed source of binary incompatibility as you add new properties to the type when all you wanted was value semantics.
  • If you want value-based classes, copy will break your constructor invariants.
  • Private constructors are basically meaningless as long as copy exists.

Consider something like this:

data class User private constructor(val name: String, val phoneNumber: String) {
    companion object {
        fun of(name: String, phoneNumber: String): Either<UserException, User> {
            return if (bad) {
                exception.left() //You can throw an exception here if you like instead.
            } else {
                User(name, phoneNumber).right()
            }
        }
    }
}

It would look like all instances of User must be valid and can't be bad, right?

Wrong:

User.of("Ahmed", "+201234567890").copy(phoneNumber = "Gotcha")

copy can bypass all the validations of your data class, it breaks your domain rules!

For more detailed explanation, check out this article.

Installation

Using plugins DSL

  • In your module-level build.gradle:
plugins {
  id "dev.ahmedmourad.nocopy.nocopy-gradle-plugin" version "1.4.0"
}

Using legacy plugin application

  • In your project-level build.gradle:
buildscript {
    repositories {
        mavenCentral()
        // Or
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "dev.ahmedmourad.nocopy:nocopy-gradle-plugin:1.4.0"
    }  
}
  • In your module-level build.gradle:
// For each module that needs to use the annotations
apply plugin: 'dev.ahmedmourad.nocopy.nocopy-gradle-plugin'

IDE Support

  • Install the IDEA plugin File -> Settings -> plugins -> Marketplace -> Kotlin NoCopy

  • Disable the default inspection File -> Settings -> Editor -> Inspections -> Kotlin -> Probably bugs -> Private data class constructor is.... Currently, you have to do this manually due to a bug with the Kotlin plugin, upvote.

Caveats

  • Kotlin compiler plugins are not a stable API. Compiled outputs from this plugin should be stable, but usage in newer versions of kotlinc are not guaranteed to be stable.

Versions

Kotlin Version NoCopy Version
1.5.0 1.4.0
1.4.32 1.3.0
1.4.20 1.2.0
1.4.0 1.1.0
1.3.72 1.0.0

License

Copyright (C) 2020 Ahmed Mourad

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
You might also like...
Build a compiler in Kotlin (based on the original tutorial by Jack Crenshaw)

Let's Build a Compiler Based on the original series "Let’s Build a Compiler!" by Jack Crenshaw. This is an adaptation of the original series to Kotlin

[prototype] Generate TypeScript interfaces from Kotlin classes

Kotlinx Serialization TypeScript Generator Kotlinx Serialization TypeScript Generator creates TypeScript interfaces from Kotlinx Serialization classes

Playground project for Koin Koin Compiler - Sandbox

Koin Compiler - Sandbox The goal of Koin compiler & Annotations project is to help declare Koin definition in a very fast and intuitive way, and gener

This repository is part of a Uni-Project to write a complete Compiler for a subset of Java.

Compiler This repository is part of a Uni-Project to write a complete Compiler for a subset of Java. Features error recovery using context sensitive a

A Open GAL compiler based on OpenGAL 0.3.1

A Open GAL compiler based on OpenGAL 0.3.1

A CLI tool to convert multi-module Jetpack Compose compiler metrics into beautiful HTML reports
A CLI tool to convert multi-module Jetpack Compose compiler metrics into beautiful HTML reports

A CLI tool to convert multi-module Jetpack Compose compiler metrics into beautiful HTML reports 1. What are Jetpack Compose compiler metrics? The Comp

This library is a set of simple wrapper classes that are aimed to help you easily access android device information.
This library is a set of simple wrapper classes that are aimed to help you easily access android device information.

SysInfo Simple, single class wrapper to get device information from an android device. This library provides an easy way to access all the device info

Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

A basic application demonstrating IPFS for collaborative data analysis, from the perspective of a Data Analysis Provider.

Spacebox A basic application demonstrating IPFS for collaborative data analysis, from the perspective of a Data Analysis Provider. Description This pr

Comments
  • Add Support for Idea 2020.3

    Add Support for Idea 2020.3

    We are currently working on a project that will make heavy use of data classes with private constructors. Having this plugin would help make the code a lot cleaner, unfortunately the plugin does not currently support the newest version of Intellij Idea

    opened by LukasPrediger 2
  • Question: Can we write our own method called copy() on a @NoCopy class?

    Question: Can we write our own method called copy() on a @NoCopy class?

    I haven't tried your plugin yet, but I'm planning on it. But I'd like to offer a copy() method of my own on my data class, that just excludes the troublesome properties, so that convenient altered-copies can still be made without risk of violating the invariants.

    Thank you!

    question 
    opened by ragnese 1
Releases(v1.3.0)
Owner
Ahmed Mourad
Android Developer
Ahmed Mourad
A Kotlin compiler plugin that allows Java callers to pass in null for default parameters

kotlin-null-defaults (Compiler plugin) (Gradle Plugin) ( Currently pending approval) A Kotlin compiler plugin that allows Java callers to pass in null

Youssef Shoaib 7 Oct 14, 2022
An annotation and Kotlin compiler plugin for enforcing a when statement is exhaustive

An annotation and Kotlin compiler plugin for enforcing a when statement is exhaustive

Cash App 468 Jan 4, 2023
A composite Github Action to execute the Kotlin Script with compiler plugin and dependency caching!

Kotlin Script Github Action Kotlin can also be used as a scripting language, which is more safer, concise, and fun to write than bash or python. Githu

Suresh 9 Nov 28, 2022
Lightweight compiler plugin intended for Kotlin/JVM library development and symbol visibility control.

Restrikt A Kotlin/JVM compiler plugin to restrict symbols access, from external project sources. This plugin offers two ways to hide symbols: An autom

Lorris Creantor 18 Nov 24, 2022
Transform java callback to kotlin suspend method.

Callback2Coroutines Transform Java callback to coroutines suspend method. 将传统Java callback 方法转换为kotlin中的suspend方法。 接入指南 根目录下加入jatpack的repository: allp

RainFool 14 May 25, 2021
A property/method accessor library for the JVM, written in Kotlin

unlok - unlock your JVM a property/method accessor library for the JVM, written in Kotlin. how to import you can import unlok from maven central just

xtrm 2 Oct 27, 2022
Clean MVVM with eliminating the usage of context from view models by introducing hilt for DI and sealed classes for displaying Errors in views using shared flows (one time event), and Stateflow for data

Clean ViewModel with Sealed Classes Following are the purposes of this repo Showing how you can remove the need of context in ViewModels. I. By using

Kashif Mehmood 22 Oct 26, 2022
A simple example of kotlim compiler plugin with FIR and IR.

A simple Kotlin compiler plugin example This Kotlin compiler plugin generates a top level class: public final class foo.bar.MyClass { fun foo(): S

Anastasiia Birillo 10 Dec 2, 2022
An experimental tool for building console UI in Kotlin using the Jetpack Compose compiler/runtime

An experimental tool for building console UI in Kotlin using the Jetpack Compose compiler/runtime

Jake Wharton 1.4k Dec 28, 2022