├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── WORKSPACE ├── java └── com │ └── google │ └── callbuilder │ ├── AtomAndVarRegistry.java │ ├── BUILD │ ├── BuilderField.java │ ├── CallBuilder.java │ ├── CallBuilderBinary.java │ ├── CallBuilderProcessor.java │ ├── FieldInfo.java │ ├── FieldStyle.java │ ├── TypeInference.java │ ├── Unification.java │ ├── UniqueSymbols.java │ ├── style │ ├── ArrayListAdding.java │ ├── BUILD │ └── StringAppending.java │ └── util │ ├── BUILD │ ├── Preconditions.java │ └── ValueType.java ├── javatests └── com │ └── google │ └── callbuilder │ ├── BUILD │ ├── CallBuilderTest.java │ ├── UnificationTest.java │ ├── WithStyleTest.java │ └── util │ ├── BUILD │ └── ValueTypeTest.java └── third_party ├── BUILD └── jsr-305 ├── .classpath ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.jdt.ui.prefs ├── BUILD ├── LICENSE ├── README.callbuilder ├── build.xml ├── nbproject └── project.xml ├── pom.xml └── src └── main └── java └── javax └── annotation ├── CheckForNull.java ├── CheckForSigned.java ├── CheckReturnValue.java ├── Detainted.java ├── MatchesPattern.java ├── Nonnegative.java ├── Nonnull.java ├── Nullable.java ├── OverridingMethodsMustInvokeSuper.java ├── ParametersAreNonnullByDefault.java ├── ParametersAreNullableByDefault.java ├── PropertyKey.java ├── RegEx.java ├── Signed.java ├── Syntax.java ├── Tainted.java ├── Untainted.java ├── WillClose.java ├── WillCloseWhenClosed.java ├── WillNotClose.java ├── concurrent ├── GuardedBy.java ├── Immutable.java ├── NotThreadSafe.java └── ThreadSafe.java └── meta ├── Exclusive.java ├── Exhaustive.java ├── TypeQualifier.java ├── TypeQualifierDefault.java ├── TypeQualifierNickname.java ├── TypeQualifierValidator.java └── When.java /.gitignore: -------------------------------------------------------------------------------- 1 | # This path comes from the base_workspace directory in a built Bazel 2 | # repository. 3 | /tools 4 | 5 | # Bazel output directory. 6 | /bazel-* 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) 6 | (CLA), which you can do online. The CLA is necessary mainly because you own the 7 | copyright to your changes, even after your contribution becomes part of our 8 | codebase, so we need your permission to use and distribute your code. We also 9 | need to be sure of various other things—for instance that you'll tell us if you 10 | know that your code infringes on other people's patents. You don't have to sign 11 | the CLA until after you've submitted your code for review and a member has 12 | approved it, but you must do it before we can put your code into our codebase. 13 | Before you start working on a larger contribution, you should get in touch with 14 | us first through the issue tracker with your idea so that we can help out and 15 | possibly guide you. Coordinating up front makes it much easier to avoid 16 | frustration later on. 17 | 18 | ### Code reviews 19 | All submissions, including submissions by project members, require review. We 20 | use Github pull requests for this purpose. 21 | 22 | ### The small print 23 | Contributions made by corporations are covered by a different agreement than 24 | the one above, the Software Grant and Corporate Contributor License Agreement. 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CallBuilder 2 | Make a builder by defining one function. 3 | (_beta_: be ready for breaking API changes) 4 | 5 | *CallBuilder* is a Java code generator that finally makes it easy to make a 6 | builder class. Builders are great when you have a constructor or method with 7 | many parameters. They are even helpful when you have two or more arguments of 8 | the same type, since the order is easy to mix up. 9 | 10 | Builders are usually hard to write. You will probably need around 4 lines for 11 | every field, and if it's an inner class, it makes the file long and cumbersome 12 | to navigate. This discourages many people from writing builders, and those 13 | people give up and learn to live with brittle, and hard-to-read code. If you 14 | want to add multiple setters for a field (common for lists that may have add and 15 | addAll), your builder will quickly become a chore to write and a burden to 16 | maintain. 17 | 18 | CallBuilder changes that. To use it, you can simply write the method or 19 | constructor as you normally would, but add the `@CallBuilder` annotation: 20 | 21 | ```java 22 | public class Person { 23 | @CallBuilder 24 | Person( 25 | String familyName, 26 | String givenName, 27 | List addressLines, 28 | @Nullable Integer age) { 29 | // ... 30 | } 31 | } 32 | ``` 33 | 34 | Now you will have access to a `PersonBuilder` class in the same package! 35 | 36 | ```java 37 | Person friend = new PersonBuilder() 38 | .setAddressLines(Arrays.asList("1123 Easy Street", "Townplace, XZ")) 39 | .setAge(22) 40 | .setGivenName("John") 41 | .setFamilyName("Doe") 42 | .build(); 43 | ``` 44 | 45 | With the field styles feature, you can define custom behavior for the fields 46 | that are of a certain type. This can make the API more natural and look more 47 | like a manually-written builder: 48 | 49 | ```java 50 | public class Person { 51 | @CallBuilder 52 | Person( 53 | String familyName, 54 | String givenName, 55 | @BuilderField(style = ArrayListAdding.class) ArrayList addressLines, 56 | @Nullable Integer age) { 57 | // ... 58 | } 59 | } 60 | ``` 61 | 62 | This can be used like: 63 | 64 | ```java 65 | Person friend = new PersonBuilder() 66 | .addToAddressLines("1123 Easy Street") 67 | .addToAddressLines("Townplace, XZ") 68 | .setAge(22) 69 | .setGivenName("John") 70 | .setFamilyName("Doe") 71 | .build(); 72 | ``` 73 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | maven_jar( 16 | name = "junit4", 17 | artifact = "junit:junit:4.11", 18 | sha1 = "4e031bb61df09069aeb2bffb4019e7a5034a4ee0", 19 | ) 20 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/AtomAndVarRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.Unification.Atom; 17 | import com.google.callbuilder.Unification.Sequence; 18 | import com.google.callbuilder.Unification.Unifiable; 19 | 20 | import java.util.ArrayList; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | import javax.lang.model.element.TypeElement; 26 | import javax.lang.model.type.DeclaredType; 27 | import javax.lang.model.type.TypeMirror; 28 | 29 | /** 30 | * Maintains a mapping of elements that must be resolved ({@link TypeElement}s and 31 | * {@link TypeParameterElements}) to objects the {@link Unification} class works with. Can also 32 | * convert the result of a successful unification into the type string that the variable expresses. 33 | */ 34 | final class AtomAndVarRegistry { 35 | /** 36 | * Mapping from Atom objects to the string representation of the item in code to which they 37 | * correspond. 38 | */ 39 | private final Map atomsToCode = new HashMap<>(); 40 | 41 | /** 42 | * The inverse of {@link #atomsToCode}. 43 | */ 44 | private final Map codeToAtoms = new HashMap<>(); 45 | 46 | String toType(Unifiable resolution) { 47 | if (resolution instanceof Atom) { 48 | return atomsToCode.get(resolution); 49 | } 50 | Sequence sequence = (Sequence) resolution; 51 | StringBuilder typeReference = new StringBuilder() 52 | .append(toType(sequence.items().get(0))); 53 | if (sequence.items().size() > 1) { 54 | String prefix = "<"; 55 | for (Unifiable unifiable : sequence.items().subList(1, sequence.items().size())) { 56 | typeReference.append(prefix); 57 | prefix = ", "; 58 | typeReference.append(toType(unifiable)); 59 | } 60 | typeReference.append(">"); 61 | } 62 | return typeReference.toString(); 63 | } 64 | 65 | private Atom atom(String codeRepresentation) { 66 | Atom atom = codeToAtoms.get(codeRepresentation); 67 | if (atom == null) { 68 | atom = new Atom(); 69 | atomsToCode.put(atom, codeRepresentation); 70 | codeToAtoms.put(codeRepresentation, atom); 71 | } 72 | return atom; 73 | } 74 | 75 | Unifiable encode(TypeMirror type, Map overridenTypeVariables) { 76 | switch (type.getKind()) { 77 | case DECLARED: 78 | List types = new ArrayList<>(); 79 | DeclaredType declaredType = (DeclaredType) type; 80 | types.add(atom(CallBuilderProcessor.qualifiedName(declaredType))); 81 | for (TypeMirror typeArgument : declaredType.getTypeArguments()) { 82 | types.add(encode(typeArgument, overridenTypeVariables)); 83 | } 84 | return new Sequence(types); 85 | case ARRAY: 86 | case BOOLEAN: 87 | case BYTE: 88 | case CHAR: 89 | case DOUBLE: 90 | case FLOAT: 91 | case INT: 92 | case LONG: 93 | case SHORT: 94 | case TYPEVAR: 95 | String stringRep = type.toString(); 96 | if (overridenTypeVariables.containsKey(stringRep)) { 97 | return overridenTypeVariables.get(stringRep); 98 | } 99 | return atom(stringRep); 100 | default: 101 | throw new RuntimeException("type is not supported for use in CallBuilder: " + type); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | ANNOTATIONS = ["BuilderField.java", "CallBuilder.java"] 16 | 17 | java_library( 18 | name = "processor_lib", 19 | srcs = glob(["*.java"], exclude = ANNOTATIONS), 20 | deps = [ 21 | ":annotations", 22 | "//java/com/google/callbuilder/util", 23 | "//third_party/jsr-305", 24 | ], 25 | visibility = ["//visibility:public"], 26 | ) 27 | 28 | java_library( 29 | name = "annotations", 30 | srcs = ANNOTATIONS, 31 | ) 32 | 33 | java_library( 34 | name = "callbuilder", 35 | exported_plugins = [":callbuilder_plugin"], 36 | exports = [":annotations"], 37 | visibility = ["//visibility:public"], 38 | ) 39 | 40 | java_plugin( 41 | name = "callbuilder_plugin", 42 | processor_class = "com.google.callbuilder.CallBuilderProcessor", 43 | deps = [ 44 | ":processor_lib", 45 | ], 46 | ) 47 | 48 | # The next two rules comprise a hack to create a deploy jar for the CallBuilder 49 | # processor. 50 | # You can build the deploy jar by executing 51 | # bazel build //java/com/google/callbuilder:CallBuilderProcessor.jar 52 | 53 | java_binary( 54 | name = "CallBuilderBinary", 55 | srcs = ["CallBuilderBinary.java"], 56 | deps = [ 57 | ":processor_lib", 58 | ":annotations", 59 | "//java/com/google/callbuilder/style", 60 | ], 61 | ) 62 | 63 | genrule( 64 | name = "generate_processor_jar", 65 | srcs = [":CallBuilderBinary_deploy.jar"], 66 | outs = ["CallBuilderProcessor.jar"], 67 | cmd = "mkdir -p META-INF/services && echo com.google.callbuilder.CallBuilderProcessor > META-INF/services/javax.annotation.processing.Processor && cp $< $@ && chmod +w $@ && zip -g $@ META-INF/services/javax.annotation.processing.Processor", 68 | ) 69 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/BuilderField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import java.lang.annotation.ElementType; 17 | import java.lang.annotation.Target; 18 | 19 | @Target({ElementType.PARAMETER}) 20 | public @interface BuilderField { 21 | Class style(); 22 | } 23 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/CallBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import java.lang.annotation.ElementType; 17 | import java.lang.annotation.Target; 18 | 19 | @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) 20 | public @interface CallBuilder { 21 | String className() default ""; 22 | String methodName() default "build"; 23 | String contextName() default "context"; 24 | } 25 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/CallBuilderBinary.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | /** 17 | * This class is only here so that we can create a {@code java_binary} target which bundles up all 18 | * the transitive dependencies needed to release as a single jar. This is a hack until Bazel 19 | * supports the same functionality with a {@code java_plugin} target, or a similar feature. 20 | */ 21 | public class CallBuilderBinary { 22 | private CallBuilderBinary() {} 23 | 24 | public static void main(String[] args) { 25 | throw new UnsupportedOperationException(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/CallBuilderProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import static javax.lang.model.element.Modifier.STATIC; 17 | 18 | import com.google.callbuilder.util.Preconditions; 19 | 20 | import java.io.IOException; 21 | import java.io.Writer; 22 | import java.util.ArrayList; 23 | import java.util.Collection; 24 | import java.util.Collections; 25 | import java.util.HashSet; 26 | import java.util.List; 27 | import java.util.Set; 28 | 29 | import javax.annotation.Nullable; 30 | import javax.annotation.processing.AbstractProcessor; 31 | import javax.annotation.processing.RoundEnvironment; 32 | import javax.lang.model.SourceVersion; 33 | import javax.lang.model.element.Element; 34 | import javax.lang.model.element.ExecutableElement; 35 | import javax.lang.model.element.PackageElement; 36 | import javax.lang.model.element.TypeElement; 37 | import javax.lang.model.element.TypeParameterElement; 38 | import javax.lang.model.element.VariableElement; 39 | import javax.lang.model.type.DeclaredType; 40 | import javax.lang.model.type.TypeKind; 41 | import javax.lang.model.type.TypeMirror; 42 | import javax.lang.model.util.ElementFilter; 43 | import javax.lang.model.util.Elements; 44 | import javax.tools.JavaFileObject; 45 | 46 | public class CallBuilderProcessor extends AbstractProcessor { 47 | @Override 48 | public Set getSupportedAnnotationTypes() { 49 | Set types = new HashSet<>(); 50 | types.add(CallBuilder.class.getName()); 51 | return types; 52 | } 53 | 54 | @Override 55 | public SourceVersion getSupportedSourceVersion() { 56 | return SourceVersion.latestSupported(); 57 | } 58 | 59 | @Override 60 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 61 | boolean claimed = (annotations.size() == 1 62 | && annotations.iterator().next().getQualifiedName().toString().equals( 63 | CallBuilder.class.getName())); 64 | if (claimed) { 65 | process(roundEnv); 66 | return true; 67 | } else { 68 | return false; 69 | } 70 | } 71 | 72 | static String capitalizeFirst(String s) { 73 | return s.substring(0, 1).toUpperCase() + s.substring(1); 74 | } 75 | 76 | List simpleNames(Iterable elements) { 77 | List names = new ArrayList<>(); 78 | for (Element el : elements) { 79 | names.add(el.getSimpleName().toString()); 80 | } 81 | return names; 82 | } 83 | 84 | private static String lines(String... separated) { 85 | StringBuilder joined = new StringBuilder(); 86 | for (String line : separated) { 87 | joined.append(line); 88 | joined.append('\n'); 89 | } 90 | return joined.toString(); 91 | } 92 | 93 | private static void writef(Writer writer, String format, Object... args) throws IOException { 94 | writer.write(String.format(format, (Object[]) args)); 95 | } 96 | 97 | private List callbuilderElements(RoundEnvironment roundEnv) { 98 | Collection unfiltered = 99 | roundEnv.getElementsAnnotatedWith(CallBuilder.class); 100 | List elements = new ArrayList<>(); 101 | elements.addAll(ElementFilter.constructorsIn(unfiltered)); 102 | elements.addAll(ElementFilter.methodsIn(unfiltered)); 103 | return elements; 104 | } 105 | 106 | /** 107 | * Information about the context of the builder. This only applies to non-static, non-constructor 108 | * methods for which a builder is being generated. If an @{@link CallBuilder}-annotated method is 109 | * not static, then the generated builder must choose on which object to call the method. This is 110 | * passed as a constructor argument to the builder. 111 | */ 112 | private static final class Context { 113 | private final TypeMirror type; 114 | private final String builderFieldName; 115 | 116 | Context(TypeMirror type, String builderFieldName) { 117 | this.type = Preconditions.checkNotNull(type); 118 | this.builderFieldName = Preconditions.checkNotNull(builderFieldName); 119 | } 120 | 121 | public TypeMirror getType() { 122 | return type; 123 | } 124 | 125 | public String getBuilderFieldName() { 126 | return builderFieldName; 127 | } 128 | } 129 | 130 | private static StringBuilder joinOn( 131 | StringBuilder builder, String delimiter, Iterable elements) { 132 | int added = 0; 133 | for (Object element : elements) { 134 | if (added++ > 0) { 135 | builder.append(delimiter); 136 | } 137 | 138 | builder.append(element.toString()); 139 | } 140 | 141 | return builder; 142 | } 143 | 144 | private static final class TypeParameters { 145 | private final List classParameters; 146 | private final List methodParameters; 147 | private final @Nullable Context context; 148 | private final boolean isConstructor; 149 | 150 | TypeParameters(List classParameters, 151 | List methodParameters, 152 | @Nullable Context context, 153 | boolean isConstructor) { 154 | this.classParameters = Collections.unmodifiableList(new ArrayList<>(classParameters)); 155 | this.methodParameters = Collections.unmodifiableList(new ArrayList<>(methodParameters)); 156 | this.context = context; 157 | this.isConstructor = isConstructor; 158 | } 159 | 160 | private List allParameters() { 161 | List allParameters = new ArrayList<>(); 162 | if ((context != null) || isConstructor) { 163 | allParameters.addAll(classParameters); 164 | } 165 | allParameters.addAll(methodParameters); 166 | return allParameters; 167 | } 168 | 169 | /** 170 | * The type parameters to place on the builder, without the "extends ..." bounds. 171 | */ 172 | String alligator() { 173 | List allParameters = allParameters(); 174 | if (allParameters.isEmpty()) { 175 | return ""; 176 | } 177 | StringBuilder alligator = new StringBuilder("<"); 178 | joinOn(alligator, ", ", allParameters); 179 | return alligator.append(">").toString(); 180 | } 181 | 182 | /** 183 | * The type parameters to place on the builder, with the "extends ..." bounds. 184 | */ 185 | String alligatorWithBounds() { 186 | List allParameters = allParameters(); 187 | if (allParameters.isEmpty()) { 188 | return ""; 189 | } 190 | 191 | StringBuilder alligator = new StringBuilder("<"); 192 | String separator = ""; 193 | for (TypeParameterElement param : allParameters) { 194 | alligator.append(separator); 195 | separator = ", "; 196 | alligator.append(param.toString()); 197 | for (TypeMirror bound : param.getBounds()) { 198 | alligator.append(" extends ").append(bound); 199 | } 200 | } 201 | return alligator.append(">").toString(); 202 | } 203 | } 204 | 205 | private void process(RoundEnvironment roundEnv) { 206 | Elements elementUtils = processingEnv.getElementUtils(); 207 | 208 | for (ExecutableElement el : callbuilderElements(roundEnv)) { 209 | boolean isConstructor = el.getSimpleName().toString().equals(""); 210 | TypeElement enclosingType = (TypeElement) el.getEnclosingElement(); 211 | UniqueSymbols uniqueSymbols = new UniqueSymbols.Builder() 212 | .addAllUserDefined(simpleNames(el.getParameters())) 213 | .build(); 214 | Context context = null; 215 | if (!isConstructor && !el.getModifiers().contains(STATIC)) { 216 | context = new Context(enclosingType.asType(), uniqueSymbols.get("")); 217 | } 218 | 219 | TypeParameters typeParameters = new TypeParameters( 220 | enclosingType.getTypeParameters(), 221 | el.getTypeParameters(), 222 | context, 223 | isConstructor); 224 | 225 | CallBuilder ann = el.getAnnotation(CallBuilder.class); 226 | String className; 227 | if (!ann.className().isEmpty()) { 228 | className = ann.className(); 229 | } else if (isConstructor) { 230 | className = enclosingType.getSimpleName() + "Builder"; 231 | } else { 232 | className = capitalizeFirst(el.getSimpleName().toString()) + "Builder"; 233 | } 234 | String packageName = packageNameOf(el); 235 | String generatedCanonicalName = 236 | packageName.isEmpty() ? className : (packageName + "." + className); 237 | try { 238 | JavaFileObject file = processingEnv.getFiler().createSourceFile(generatedCanonicalName, el); 239 | try (Writer wrt = file.openWriter()) { 240 | if (!packageName.isEmpty()) { 241 | writef(wrt, lines( 242 | "package %s;", 243 | ""), 244 | packageName); 245 | } 246 | 247 | writef(wrt, lines( 248 | "@javax.annotation.Generated(\"%s\")"), 249 | CallBuilderProcessor.class.getName()); 250 | writef(wrt, lines( 251 | "public final class %s%s {"), 252 | className, typeParameters.alligatorWithBounds()); 253 | 254 | if (context != null) { 255 | String constructorParameterName = ann.contextName(); 256 | writef(wrt, lines( 257 | " private final %s %s;", 258 | " public %s(%s %s) {", 259 | " %s = %s;", 260 | " }"), 261 | context.getType(), context.getBuilderFieldName(), 262 | className, context.getType(), constructorParameterName, 263 | context.getBuilderFieldName(), constructorParameterName); 264 | } 265 | 266 | List fields = FieldInfo.fromAll(elementUtils, el.getParameters()); 267 | 268 | for (FieldInfo field : fields) { 269 | if (field.style() != null) { 270 | FieldStyle fieldStyle = field.style(); 271 | TypeInference inference = TypeInference.forField(fieldStyle, field.parameter()); 272 | if (inference != null) { 273 | writef(wrt, lines(" private %s %s = %s.start();"), 274 | inference.builderFieldType(), field.name(), 275 | qualifiedName(fieldStyle.styleClass())); 276 | for (ExecutableElement modifier : fieldStyle.modifiers()) { 277 | List parameters = modifier.getParameters(); 278 | List nonFieldParameterNames = 279 | simpleNames(parameters.subList(1, parameters.size())); 280 | List nonFieldParameterTypes = 281 | inference.modifierParameterTypes(modifier); 282 | if (nonFieldParameterTypes != null) { 283 | writef(wrt, lines( 284 | " public %s%s %s%s(%s) {", 285 | " this.%s = %s.%s(this.%s, %s);", 286 | " return this;", 287 | " }"), 288 | className, typeParameters.alligator(), 289 | modifier.getSimpleName(), capitalizeFirst(field.name()), 290 | parameterList(nonFieldParameterTypes, nonFieldParameterNames), 291 | 292 | field.name(), 293 | qualifiedName(fieldStyle.styleClass()), modifier.getSimpleName(), 294 | field.name(), joinOn(new StringBuilder(), ", ", nonFieldParameterNames)); 295 | } 296 | // TODO: report warning if could not inference parameter types for some modifier. 297 | // TODO: support generic type parameters on the *generated* modifier 298 | } 299 | } 300 | // TODO: report error if TypeInference could not be obtained. 301 | } else { 302 | writef(wrt, lines( 303 | " private %s %s;", 304 | " public %s%s set%s(%s %s) {", 305 | " this.%s = %s;", 306 | " return this;", 307 | " }"), 308 | field.finishType(), field.name(), 309 | 310 | className, typeParameters.alligator(), 311 | capitalizeFirst(field.name()), field.finishType(), field.name(), 312 | 313 | field.name(), field.name()); 314 | } 315 | } 316 | 317 | TypeMirror generatedMethodReturn; 318 | if (isConstructor) { 319 | generatedMethodReturn = enclosingType.asType(); 320 | } else { 321 | generatedMethodReturn = el.getReturnType(); 322 | } 323 | 324 | // invocation: the return expression of the generated method, minus the argument list. 325 | String invocation; 326 | if (isConstructor) { 327 | invocation = String.format("new %s%s", 328 | enclosingType.getQualifiedName(), 329 | typeParameters.alligator()); 330 | } else { 331 | invocation = String.format("%s.%s", 332 | (context != null) 333 | ? context.getBuilderFieldName() 334 | : enclosingType.getQualifiedName(), 335 | el.getSimpleName()); 336 | } 337 | 338 | writef(wrt, lines( 339 | " public %s %s() {", 340 | " %s%s(%s);", 341 | " }", 342 | "}"), 343 | generatedMethodReturn, ann.methodName(), 344 | 345 | (generatedMethodReturn.getKind() == TypeKind.VOID) ? "" : "return ", 346 | invocation, finishInvocations(fields)); 347 | } 348 | } catch (IOException e) { 349 | throw new RuntimeException(e); 350 | } 351 | } 352 | } 353 | 354 | /** 355 | * Returns the name of the package that the given element is in. If the element is in the default 356 | * (unnamed) package then the name is the empty string. Taken from AutoValue source code. 357 | */ 358 | static String packageNameOf(Element el) { 359 | while (true) { 360 | Element enclosing = el.getEnclosingElement(); 361 | if (enclosing instanceof PackageElement) { 362 | return ((PackageElement) enclosing).getQualifiedName().toString(); 363 | } 364 | el = (Element) enclosing; 365 | } 366 | } 367 | 368 | private static String parameterList(List parameterTypes, List parameterNames) { 369 | StringBuilder list = new StringBuilder(); 370 | for (int i = 0; i < parameterTypes.size(); i++) { 371 | if (i != 0) { 372 | list.append(", "); 373 | } 374 | list.append(parameterTypes.get(i)).append(" ").append(parameterNames.get(i)); 375 | } 376 | return list.toString(); 377 | } 378 | 379 | static String qualifiedName(DeclaredType type) { 380 | return ((TypeElement) type.asElement()).getQualifiedName().toString(); 381 | } 382 | 383 | private static String finishInvocations(Iterable fields) { 384 | StringBuilder invocations = new StringBuilder(); 385 | for (FieldInfo field : fields) { 386 | if (invocations.length() != 0) { 387 | invocations.append(", "); 388 | } 389 | if (field.style() != null) { 390 | invocations.append(String.format("%s.finish(%s)", 391 | qualifiedName(field.style().styleClass()), field.name())); 392 | } else { 393 | invocations.append(field.name()); 394 | } 395 | } 396 | return invocations.toString(); 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/FieldInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.util.Preconditions; 17 | import com.google.callbuilder.util.ValueType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | import javax.annotation.Nullable; 24 | import javax.lang.model.element.AnnotationMirror; 25 | import javax.lang.model.element.AnnotationValue; 26 | import javax.lang.model.element.ExecutableElement; 27 | import javax.lang.model.element.VariableElement; 28 | import javax.lang.model.type.DeclaredType; 29 | import javax.lang.model.util.Elements; 30 | 31 | final class FieldInfo extends ValueType { 32 | private final VariableElement parameter; 33 | private final @Nullable FieldStyle style; 34 | 35 | FieldInfo(VariableElement parameter, @Nullable FieldStyle style) { 36 | this.parameter = Preconditions.checkNotNull(parameter); 37 | this.style = style; 38 | } 39 | 40 | @Override 41 | protected void addFields(FieldReceiver fields) { 42 | fields.add("parameter", parameter); 43 | fields.add("style", style); 44 | } 45 | 46 | /** 47 | * Method parameter from which this field was automatically generated. 48 | */ 49 | VariableElement parameter() { 50 | return parameter; 51 | } 52 | 53 | @Nullable FieldStyle style() { 54 | return style; 55 | } 56 | 57 | /** 58 | * The name of this field, which is used in the builder method names. This is the name of the 59 | * original {@link parameter()}. 60 | */ 61 | String name() { 62 | return parameter().getSimpleName().toString(); 63 | } 64 | 65 | /** 66 | * The type of the field after it is converted by the style's {@code finish} method. 67 | */ 68 | String finishType() { 69 | return parameter().asType().toString(); 70 | } 71 | 72 | static FieldInfo from(Elements elementUtils, VariableElement parameter) { 73 | FieldStyle style = null; 74 | 75 | // Look for style field on the @BuilderField annotation. If the annotation is 76 | // present, the value of that field overrides the default set above. 77 | for (AnnotationMirror ann : parameter.getAnnotationMirrors()) { 78 | if (ann.getAnnotationType().toString() 79 | .equals(BuilderField.class.getCanonicalName())) { 80 | for (Map.Entry annEl : 81 | ann.getElementValues().entrySet()) { 82 | if ("style".equals(annEl.getKey().getSimpleName().toString())) { 83 | style = FieldStyle.fromStyleClass((DeclaredType) annEl.getValue().getValue()); 84 | } 85 | } 86 | } 87 | } 88 | 89 | return new FieldInfo(parameter, style); 90 | } 91 | 92 | static List fromAll( 93 | Elements elementUtils, Iterable parameters) { 94 | List fields = new ArrayList<>(); 95 | for (VariableElement parameter : parameters) { 96 | fields.add(from(elementUtils, parameter)); 97 | } 98 | return fields; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/FieldStyle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.util.Preconditions; 17 | import com.google.callbuilder.util.ValueType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import javax.lang.model.element.ExecutableElement; 24 | import javax.lang.model.type.DeclaredType; 25 | import javax.lang.model.util.ElementFilter; 26 | 27 | final class FieldStyle extends ValueType { 28 | private final DeclaredType styleClass; 29 | private final List modifiers; 30 | private final ExecutableElement start; 31 | private final ExecutableElement finish; 32 | 33 | FieldStyle(DeclaredType styleClass, List modifiers, 34 | ExecutableElement start, ExecutableElement finish) { 35 | this.styleClass = Preconditions.checkNotNull(styleClass); 36 | this.modifiers = Collections.unmodifiableList(new ArrayList<>(modifiers)); 37 | this.start = Preconditions.checkNotNull(start); 38 | this.finish = Preconditions.checkNotNull(finish); 39 | } 40 | 41 | @Override 42 | protected void addFields(FieldReceiver fields) { 43 | fields.add("styleClass", styleClass); 44 | fields.add("modifiers", modifiers); 45 | fields.add("start", start); 46 | fields.add("finish", finish); 47 | } 48 | 49 | /** 50 | * The type corresponding to the field's style, which may be customized with the 51 | * @{@link BuilderField} annotation. 52 | */ 53 | DeclaredType styleClass() { 54 | return styleClass; 55 | } 56 | 57 | List modifiers() { 58 | return modifiers; 59 | } 60 | 61 | ExecutableElement start() { 62 | return start; 63 | } 64 | 65 | ExecutableElement finish() { 66 | return finish; 67 | } 68 | 69 | public static FieldStyle fromStyleClass(DeclaredType styleClass) { 70 | List modifiers = new ArrayList<>(); 71 | ExecutableElement start = null; 72 | ExecutableElement finish = null; 73 | 74 | for (ExecutableElement modifier : 75 | ElementFilter.methodsIn(styleClass.asElement().getEnclosedElements())) { 76 | String name = modifier.getSimpleName().toString(); 77 | if (name.equals("start")) { 78 | start = modifier; 79 | } else if (name.equals("finish")) { 80 | finish = modifier; 81 | } else { 82 | modifiers.add(modifier); 83 | } 84 | } 85 | 86 | if(start == null || finish == null) { 87 | throw new IllegalArgumentException(String.format( 88 | "could not find start() and/or finish() method on BuilderField style class %s", 89 | styleClass)); 90 | } 91 | 92 | return new FieldStyle(styleClass, modifiers, start, finish); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/TypeInference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.Unification.Sequence; 17 | import com.google.callbuilder.Unification.Substitution; 18 | import com.google.callbuilder.Unification.Unifiable; 19 | import com.google.callbuilder.Unification.Variable; 20 | import com.google.callbuilder.util.Preconditions; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | import javax.annotation.Nullable; 29 | import javax.lang.model.element.ExecutableElement; 30 | import javax.lang.model.element.TypeParameterElement; 31 | import javax.lang.model.element.VariableElement; 32 | import javax.lang.model.element.VariableElement; 33 | import javax.lang.model.element.VariableElement; 34 | 35 | /** 36 | * Utility methods for inferring the types of things. 37 | */ 38 | final class TypeInference { 39 | private final AtomAndVarRegistry registry; 40 | private final Unifiable builderFieldType; 41 | 42 | TypeInference(AtomAndVarRegistry registry, Unifiable builderFieldType) { 43 | this.registry = Preconditions.checkNotNull(registry); 44 | this.builderFieldType = Preconditions.checkNotNull(builderFieldType); 45 | } 46 | 47 | private static Map overridenTypeVariables(ExecutableElement method) { 48 | Map variables = new HashMap<>(); 49 | for (TypeParameterElement typeParameter : method.getTypeParameters()) { 50 | variables.put(typeParameter.toString(), new Variable()); 51 | } 52 | return variables; 53 | } 54 | 55 | /** 56 | * Attempts to perform type inference for the field that has the given style. 57 | * @param fieldStyle the style of the field 58 | * @param parameter the original parameter on the annotated method for which the field is being 59 | * generated 60 | */ 61 | static @Nullable TypeInference forField(FieldStyle fieldStyle, VariableElement parameter) { 62 | List lhs = new ArrayList<>(); 63 | List rhs = new ArrayList<>(); 64 | AtomAndVarRegistry registry = new AtomAndVarRegistry(); 65 | 66 | Variable builderFieldType = new Variable(); 67 | Map startOverridenTypeVariables = 68 | overridenTypeVariables(fieldStyle.start()); 69 | Map finishOverridenTypeVariables = 70 | overridenTypeVariables(fieldStyle.finish()); 71 | 72 | // The generic type parameters of the start and finish method are actually variables in 73 | // unification, while type parameters of enclosing classes etc. are not. Override the 74 | // start/finish type parameters. 75 | 76 | // Each .add pair represents an equality constraint. 77 | 78 | // The return of start() must match the type of the builder field. 79 | lhs.add(registry.encode( 80 | fieldStyle.start().getReturnType(), 81 | startOverridenTypeVariables)); 82 | rhs.add(builderFieldType); 83 | 84 | // The parameter type of finish() must also match the type of the builder field. 85 | lhs.add(builderFieldType); 86 | List finishParameters = fieldStyle.finish().getParameters(); 87 | // TODO: report an error if the number of elements in finishParameters is not 1. 88 | rhs.add(registry.encode( 89 | finishParameters.get(0).asType(), 90 | finishOverridenTypeVariables)); 91 | 92 | // The return type of finish() must match the value expected by the annotated method. 93 | lhs.add(registry.encode( 94 | fieldStyle.finish().getReturnType(), 95 | finishOverridenTypeVariables)); 96 | rhs.add(registry.encode(parameter.asType(), Collections.emptyMap())); 97 | 98 | Substitution result = Unification.unify(new Sequence(lhs), new Sequence(rhs)); 99 | if (result != null) { 100 | return new TypeInference(registry, result.resolve(builderFieldType)); 101 | } else { 102 | return null; 103 | } 104 | } 105 | 106 | /** 107 | * Returns the fully-qualified name of the field in the builder. This type is dictated by: 108 | *
    109 | *
  • the type the annotated method expects in its parameter list 110 | *
  • the type the type returned by the {@link BuilderField} style's {@code start()} method 111 | *
  • the type accepted by the {@link BuilderField} style's {@code finish()} method 112 | *
  • the type returned by the {@link BuilderField} style's {@code finish()} method 113 | *
114 | * The {@code finish()} method can perform arbitrary changes to the builder field, so this is not 115 | * as simple as it first seems. For instance, the {@code finish()} method may convert a Guava 116 | * {@code Optional} to a nullable field, or vice-versa. 117 | */ 118 | String builderFieldType() { 119 | return registry.toType(builderFieldType); 120 | } 121 | 122 | /** 123 | * Returns the fully-qualified types of each parameter in the generated modifier, or 124 | * {@code null} if unification failed. 125 | */ 126 | @Nullable List modifierParameterTypes(ExecutableElement modifier) { 127 | Map overridenTypeVariables = overridenTypeVariables(modifier); 128 | 129 | Substitution result = Unification.unify( 130 | builderFieldType, registry.encode(modifier.getReturnType(), overridenTypeVariables)); 131 | if (result != null) { 132 | List parameterTypes = new ArrayList<>(); 133 | List parameters = modifier.getParameters(); 134 | for (VariableElement parameter : parameters.subList(1, parameters.size())) { 135 | parameterTypes.add( 136 | registry.toType( 137 | result.resolve( 138 | registry.encode(parameter.asType(), overridenTypeVariables)))); 139 | } 140 | return parameterTypes; 141 | } 142 | return null; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/Unification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.util.Preconditions; 17 | import com.google.callbuilder.util.ValueType; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | import javax.annotation.Nullable; 26 | 27 | /** 28 | * Performs symbolic unification. 29 | */ 30 | final class Unification { 31 | private Unification() {} 32 | 33 | static interface Unifiable { 34 | Unifiable apply(Map substitutions); 35 | } 36 | 37 | static final class Atom implements Unifiable { 38 | @Override 39 | public Unifiable apply(Map substitutions) { 40 | return this; 41 | } 42 | } 43 | 44 | static final class Variable implements Unifiable { 45 | @Override 46 | public Unifiable apply(Map substitutions) { 47 | return substitutions.containsKey(this) ? substitutions.get(this) : this; 48 | } 49 | } 50 | 51 | static final class Sequence extends ValueType implements Unifiable { 52 | private final List items; 53 | 54 | Sequence(List items) { 55 | this.items = Collections.unmodifiableList(new ArrayList(items)); 56 | } 57 | 58 | List items() { 59 | return items; 60 | } 61 | 62 | @Override 63 | protected void addFields(FieldReceiver fields) { 64 | fields.add("items", items); 65 | } 66 | 67 | @Override 68 | public Unifiable apply(Map substitutions) { 69 | return sequenceApply(substitutions, items()); 70 | } 71 | } 72 | 73 | private static Sequence sequenceApply( 74 | Map substitutions, Iterable items) { 75 | List newItems = new ArrayList<>(); 76 | for (Unifiable oldItem : items) { 77 | newItems.add(oldItem.apply(substitutions)); 78 | } 79 | return new Sequence(newItems); 80 | } 81 | 82 | /** 83 | * Applies s1 to the elements of s2 and adds them into a single list. 84 | */ 85 | static final Map compose( 86 | Map s1, Map s2) { 87 | Map composed = new HashMap<>(); 88 | composed.putAll(s1); 89 | for (Map.Entry entry2 : s2.entrySet()) { 90 | composed.put(entry2.getKey(), entry2.getValue().apply(s1)); 91 | } 92 | return composed; 93 | } 94 | 95 | private static @Nullable Substitution sequenceUnify(Sequence lhs, Sequence rhs) { 96 | if (lhs.items().size() != rhs.items().size()) { 97 | return null; 98 | } 99 | if (lhs.items().isEmpty()) { 100 | return EMPTY; 101 | } 102 | Unifiable firstLhs = lhs.items().get(0); 103 | Unifiable firstRhs = rhs.items().get(0); 104 | Substitution subs1 = unify(firstLhs, firstRhs); 105 | if (subs1 != null) { 106 | Sequence restLhs = sequenceApply(subs1.resultMap(), lhs.items().subList(1, lhs.items().size())); 107 | Sequence restRhs = sequenceApply(subs1.resultMap(), rhs.items().subList(1, rhs.items().size())); 108 | Substitution subs2 = sequenceUnify(restLhs, restRhs); 109 | if (subs2 != null) { 110 | Map joined = new HashMap<>(); 111 | joined.putAll(subs1.resultMap()); 112 | joined.putAll(subs2.resultMap()); 113 | return new Substitution(joined); 114 | } 115 | } 116 | return null; 117 | } 118 | 119 | static @Nullable Substitution unify(Unifiable lhs, Unifiable rhs) { 120 | if (lhs instanceof Variable) { 121 | return new Substitution(Collections.singletonMap((Variable) lhs, rhs)); 122 | } 123 | if (rhs instanceof Variable) { 124 | return new Substitution(Collections.singletonMap((Variable) rhs, lhs)); 125 | } 126 | if (lhs instanceof Atom && rhs instanceof Atom) { 127 | return lhs == rhs ? EMPTY : null; 128 | } 129 | if (lhs instanceof Sequence && rhs instanceof Sequence) { 130 | return sequenceUnify((Sequence) lhs, (Sequence) rhs); 131 | } 132 | return null; 133 | } 134 | 135 | /** 136 | * The results of a successful unification. This object gives access to the raw variable mapping 137 | * that resulted from the algorithm, but also supplies functionality for resolving a variable to 138 | * the fullest extent possible with the {@code resolve} method. 139 | */ 140 | static final class Substitution extends ValueType { 141 | private final Map resultMap; 142 | 143 | Substitution(Map resultMap) { 144 | this.resultMap = Collections.unmodifiableMap(new HashMap<>(resultMap)); 145 | } 146 | 147 | /** 148 | * The result of the unification algorithm proper. This does not have everything completely 149 | * resolved - some variable substitutions are required before getting the most atom-y 150 | * representation. 151 | */ 152 | Map resultMap() { 153 | return resultMap; 154 | } 155 | 156 | @Override 157 | protected void addFields(FieldReceiver fields) { 158 | fields.add("resultMap", resultMap); 159 | } 160 | 161 | final Unifiable resolve(Unifiable unifiable) { 162 | Unifiable previous; 163 | Unifiable current = unifiable; 164 | do { 165 | previous = current; 166 | current = current.apply(resultMap()); 167 | } while (!current.equals(previous)); 168 | return current; 169 | } 170 | } 171 | 172 | private static final Substitution EMPTY = 173 | new Substitution(Collections.emptyMap()); 174 | } 175 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/UniqueSymbols.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.util.Preconditions; 17 | 18 | import java.util.Collection; 19 | import java.util.Collections; 20 | import java.util.HashMap; 21 | import java.util.HashSet; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | /** 26 | * Generates unique identifiers given ones that are declared or used by the user. 27 | */ 28 | public final class UniqueSymbols { 29 | public static final class Builder { 30 | private final Set userDefined = new HashSet<>(); 31 | 32 | public Builder addUserDefined(String name) { 33 | userDefined.add(name); 34 | return this; 35 | } 36 | 37 | public Builder addAllUserDefined(Collection names) { 38 | userDefined.addAll(names); 39 | return this; 40 | } 41 | 42 | public UniqueSymbols build() { 43 | return new UniqueSymbols(userDefined); 44 | } 45 | } 46 | 47 | private final Set userDefined; 48 | 49 | private final Map cached; 50 | private final Set used; 51 | 52 | private UniqueSymbols(Set userDefined) { 53 | this.userDefined = Collections.unmodifiableSet(new HashSet<>(userDefined)); 54 | 55 | this.cached = new HashMap<>(); 56 | this.used = new HashSet<>(); 57 | this.used.addAll(userDefined); 58 | } 59 | 60 | public Set getUserDefined() { 61 | return userDefined; 62 | } 63 | 64 | private static String template(String desired, int tryIndex) { 65 | return String.format("%s_gensym_%d", desired, tryIndex); 66 | } 67 | 68 | /** 69 | * Returns a unique name which can be used for an identifier generated implicitly. Note that this 70 | * method returns differing {@link String}s even when called repeatedly with the same value for 71 | * {@code desired}. This is to encourage storing the generated name elsewhere, which avoids typos 72 | * and discourages implicit naming conventions. 73 | */ 74 | public String get(String desired) { 75 | if (cached.containsKey(desired)) { 76 | return cached.get(desired); 77 | } 78 | 79 | int tryIndex = 0; 80 | while (true) { 81 | String collisionCheck = template(desired, tryIndex); 82 | if (used.add(collisionCheck)) { 83 | cached.put(desired, collisionCheck); 84 | return collisionCheck; 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/style/ArrayListAdding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder.style; 15 | 16 | import java.util.ArrayList; 17 | 18 | public class ArrayListAdding { 19 | private ArrayListAdding() {} 20 | 21 | public static ArrayList start() { 22 | return new ArrayList<>(); 23 | } 24 | 25 | public static ArrayList finish(ArrayList list) { 26 | return list; 27 | } 28 | 29 | public static ArrayList addTo(ArrayList to, T item) { 30 | to.add(item); 31 | return to; 32 | } 33 | 34 | public static ArrayList addAllTo(ArrayList to, Iterable items) { 35 | for (T item : items) { 36 | to.add(item); 37 | } 38 | return to; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/style/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Defines some default and generally useful field styles. These are optional 16 | # when using CallBuilder. 17 | java_library( 18 | name = "style", 19 | srcs = glob(["*.java"]), 20 | visibility = ["//visibility:public"], 21 | ) 22 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/style/StringAppending.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder.style; 15 | 16 | public class StringAppending { 17 | private StringAppending() {} 18 | 19 | public static StringBuilder start() { 20 | return new StringBuilder(); 21 | } 22 | 23 | public static String finish(StringBuilder from) { 24 | return from.toString(); 25 | } 26 | 27 | public static StringBuilder appendTo(StringBuilder start, String value) { 28 | return start.append(value); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/util/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | java_library( 16 | name = "util", 17 | srcs = glob(["*.java"]), 18 | visibility = ["//visibility:public"], 19 | ) 20 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/util/Preconditions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder.util; 15 | 16 | /** 17 | * Utility code for checking preconditions of methods and constructors. 18 | */ 19 | public class Preconditions { 20 | /** 21 | * Checks if the given value is {@code null}. 22 | * 23 | * @throws NullPointerException if {@code value} is {@code null} 24 | * @return the {@code value} argument unchanged 25 | */ 26 | public static T checkNotNull(T value) { 27 | if (value == null) { 28 | throw new NullPointerException(); 29 | } 30 | 31 | return value; 32 | } 33 | 34 | private Preconditions() {} 35 | } 36 | -------------------------------------------------------------------------------- /java/com/google/callbuilder/util/ValueType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.callbuilder.util; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * Represents an instance that compares in {@link Object#hashCode()} and 23 | * {@link Object#equals(Object)} using a sequence of fields. If two instances have the same runtime 24 | * class and the same sequence of fields, then they are considered equal. 25 | * 26 | *

This class implements the two {@link Object} methods mentioned above as well as 27 | * {@link Object#toString()}. 28 | */ 29 | public abstract class ValueType { 30 | /** 31 | * An object that receives fields (names and current values) for processing. It is assumed that 32 | * for a given class, the order of fields is always the same, although individual fields may be 33 | * omitted. 34 | */ 35 | public interface FieldReceiver { 36 | void add(String name, Object value); 37 | } 38 | 39 | /** A receiver that adds all received field names and values into a list in order. */ 40 | private static final class ReceiverIntoList implements FieldReceiver { 41 | private final List list = new ArrayList(); 42 | 43 | @Override 44 | public void add(String name, Object value) { 45 | list.add(name); 46 | list.add(value); 47 | } 48 | 49 | public List get() { 50 | return list; 51 | } 52 | } 53 | 54 | /** A receiver that uses each received name and value to calculate a hash code. */ 55 | private static final class ReceiverIntoHashCode implements FieldReceiver { 56 | private int hashCode = 1; 57 | 58 | private void add(Object value) { 59 | hashCode *= 31; 60 | hashCode += (value == null) ? 0 : value.hashCode(); 61 | } 62 | 63 | @Override 64 | public void add(String name, Object value) { 65 | add(name); 66 | add(value); 67 | } 68 | 69 | public int get() { 70 | return hashCode; 71 | } 72 | } 73 | 74 | /** 75 | * A receiver that puts each name and value into a {@link StringBuilder} that generates a human- 76 | * readable representation of the value. 77 | */ 78 | private static final class ReceiverIntoStringBuilder implements FieldReceiver { 79 | private final StringBuilder builder; 80 | private String delimiter; 81 | 82 | ReceiverIntoStringBuilder(StringBuilder builder) { 83 | this.builder = builder; 84 | this.delimiter = ""; 85 | } 86 | 87 | @Override 88 | public void add(String name, Object value) { 89 | builder.append(delimiter); 90 | delimiter = ", "; 91 | builder.append(name).append("=").append(value); 92 | } 93 | } 94 | 95 | /** Implement this method to report the name and value of each field. */ 96 | protected abstract void addFields(FieldReceiver fields); 97 | 98 | @Override 99 | public final boolean equals(Object obj) { 100 | if ((obj == null) || (obj.getClass() != this.getClass())) { 101 | return false; 102 | } 103 | ReceiverIntoList a = new ReceiverIntoList(); 104 | ReceiverIntoList b = new ReceiverIntoList(); 105 | this.addFields(a); 106 | ((ValueType) obj).addFields(b); 107 | return a.get().equals(b.get()); 108 | } 109 | 110 | @Override 111 | public final int hashCode() { 112 | ReceiverIntoHashCode receiver = new ReceiverIntoHashCode(); 113 | addFields(receiver); 114 | return receiver.get(); 115 | } 116 | 117 | @Override 118 | public String toString() { 119 | StringBuilder builder = new StringBuilder(); 120 | builder.append(getClass().getSimpleName()) 121 | .append("{"); 122 | 123 | addFields(new ReceiverIntoStringBuilder(builder)); 124 | 125 | return builder.append("}") 126 | .toString(); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | package(default_testonly = 1) 16 | 17 | java_test( 18 | name = "CallBuilderTest", 19 | srcs = ["CallBuilderTest.java"], 20 | deps = [ 21 | "//java/com/google/callbuilder", 22 | "//java/com/google/callbuilder/util", 23 | "//third_party:junit4", 24 | ], 25 | ) 26 | 27 | # Makes sure that we can use functionality given in the style library. 28 | java_test( 29 | name = "WithStyleTest", 30 | srcs = ["WithStyleTest.java"], 31 | deps = [ 32 | "//java/com/google/callbuilder", 33 | "//java/com/google/callbuilder/style", 34 | "//third_party:junit4", 35 | ], 36 | ) 37 | 38 | java_test( 39 | name = "UnificationTest", 40 | srcs = ["UnificationTest.java"], 41 | deps = [ 42 | "//java/com/google/callbuilder:processor_lib", 43 | "//third_party:junit4", 44 | ], 45 | ) 46 | -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/CallBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.util.Preconditions; 17 | import java.lang.reflect.Modifier; 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | import org.junit.Assert; 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.junit.runners.JUnit4; 28 | 29 | @RunWith(JUnit4.class) 30 | public class CallBuilderTest { 31 | static class ConfusingSignatures { 32 | int addOffset; 33 | 34 | @CallBuilder(className = "NonStaticAdder") 35 | int add(int x, int y, int z) { 36 | return addOffset + x + y + z; 37 | } 38 | 39 | @CallBuilder(className = "StaticConcater") 40 | static String add(String left, String right) { 41 | return left + right; 42 | } 43 | 44 | @CallBuilder(className = "HasGenericsContainsCheck") 45 | static boolean checkContains(Map map, String key, int value) { 46 | return Integer.valueOf(value).equals(map.get(key)); 47 | } 48 | 49 | @CallBuilder 50 | static Map singletonMap(String key, String value) { 51 | return Collections.singletonMap(key, value); 52 | } 53 | } 54 | 55 | static class HasGen { 56 | int which; 57 | 58 | @CallBuilder 59 | E pickSome(E first, E second, E third) { 60 | switch (which) { 61 | case 0: 62 | return first; 63 | case 1: 64 | return second; 65 | default: 66 | return third; 67 | } 68 | } 69 | 70 | @CallBuilder 71 | static int pickSecond(int first, int second, int third) { 72 | return second; 73 | } 74 | 75 | @CallBuilder(className = "ThreeInListBuilder") 76 | List toList(F first, F second, F third) { 77 | return Arrays.asList(first, second, third); 78 | } 79 | 80 | @CallBuilder(className = "CopyAppender", methodName = "append") 81 | static List copyAppend(Iterable allButLast, F last) { 82 | List result = new ArrayList<>(); 83 | for (F element : allButLast) { 84 | result.add(element); 85 | } 86 | result.add(last); 87 | return result; 88 | } 89 | } 90 | 91 | static class Container { 92 | final I item; 93 | 94 | @CallBuilder 95 | Container(I item) { 96 | this.item = item; 97 | } 98 | } 99 | 100 | static class Name { 101 | String family; 102 | String given; 103 | 104 | @CallBuilder 105 | Name(String family, String given) { 106 | this.family = Preconditions.checkNotNull(family); 107 | this.given = Preconditions.checkNotNull(given); 108 | } 109 | } 110 | 111 | @Test 112 | public void nonStaticMethod() { 113 | ConfusingSignatures signatures = new ConfusingSignatures(); 114 | signatures.addOffset = 1000; 115 | int result = new NonStaticAdder(signatures) 116 | .setX(100) 117 | .setY(10) 118 | .setZ(1) 119 | .build(); 120 | Assert.assertEquals(1111, result); 121 | } 122 | 123 | @Test 124 | public void staticMethod() { 125 | Assert.assertEquals( 126 | "foobar", 127 | new StaticConcater().setLeft("foo").setRight("bar").build()); 128 | } 129 | 130 | @Test 131 | public void genericsInParameters() { 132 | Map map = new HashMap<>(); 133 | map.put("foo", 999); 134 | map.put("bar", 1000); 135 | Assert.assertEquals(false, new HasGenericsContainsCheck() 136 | .setMap(map) 137 | .setKey("foo") 138 | .setValue(888) 139 | .build()); 140 | Assert.assertEquals(true, new HasGenericsContainsCheck() 141 | .setMap(map) 142 | .setKey("foo") 143 | .setValue(999) 144 | .build()); 145 | } 146 | 147 | @Test 148 | public void returnIsGeneric() { 149 | Assert.assertEquals(Collections.singletonMap("a", "b"), 150 | new SingletonMapBuilder().setKey("a").setValue("b").build()); 151 | } 152 | 153 | @Test 154 | public void genericEnclosingClassButMethodIsStatic() { 155 | Assert.assertEquals(101, 156 | new PickSecondBuilder() 157 | .setFirst(99) 158 | .setSecond(101) 159 | .setThird(8) 160 | .build()); 161 | } 162 | 163 | @Test 164 | public void genericEnclosingClass() { 165 | HasGen> hasGen = new HasGen<>(); 166 | hasGen.which = 1; 167 | Assert.assertEquals( 168 | Collections.singletonMap("a", "b"), 169 | new PickSomeBuilder>(hasGen) 170 | .setSecond(Collections.singletonMap("a", "b")) 171 | .build()); 172 | } 173 | 174 | @Test 175 | public void differentGenericArgsOnEnclosingClassAndMethod() { 176 | HasGen> hasGen = new HasGen<>(); 177 | ArrayList first = new ArrayList<>(); 178 | ArrayList second = new ArrayList<>(); 179 | ArrayList third = new ArrayList<>(); 180 | 181 | List> result = 182 | new ThreeInListBuilder, ArrayList>(hasGen) 183 | .setFirst(first) 184 | .setSecond(second) 185 | .setThird(third) 186 | .build(); 187 | Assert.assertSame(first, result.get(0)); 188 | Assert.assertSame(second, result.get(1)); 189 | Assert.assertSame(third, result.get(2)); 190 | } 191 | 192 | @Test 193 | public void genericArgsOnMethodAndContainingClassButMethodIsStatic() { 194 | List numbers = new CopyAppender() 195 | .setAllButLast(Arrays.asList(1, 2)) 196 | .setLast(3) 197 | .append(); 198 | 199 | Assert.assertEquals(Arrays.asList(1, 2, 3), numbers); 200 | } 201 | 202 | @Test 203 | public void builderForConstructorOnGenericClass() { 204 | Container c = new ContainerBuilder() 205 | .setItem(":)") 206 | .build(); 207 | Assert.assertEquals(":)", c.item); 208 | } 209 | 210 | @Test 211 | public void builderForConstructorOnNonGenericClass() { 212 | Name n = new NameBuilder().setGiven("Eric").setFamily("Schmidt").build(); 213 | Assert.assertEquals("Eric", n.given); 214 | Assert.assertEquals("Schmidt", n.family); 215 | } 216 | 217 | @Test 218 | public void buildMethodIsPublic() throws Exception { 219 | Assert.assertEquals(Modifier.PUBLIC, NameBuilder.class.getMethod("build").getModifiers() & Modifier.PUBLIC); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/UnificationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.Unification.Atom; 17 | import com.google.callbuilder.Unification.Sequence; 18 | import com.google.callbuilder.Unification.Substitution; 19 | import com.google.callbuilder.Unification.Unifiable; 20 | import com.google.callbuilder.Unification.Variable; 21 | 22 | import org.junit.Assert; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.junit.runners.JUnit4; 26 | 27 | import java.util.Arrays; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | 31 | @RunWith(JUnit4.class) 32 | public class UnificationTest { 33 | private Atom a = new Atom(); 34 | private Atom b = new Atom(); 35 | private Atom c = new Atom(); 36 | private Variable x = new Variable(); 37 | private Variable y = new Variable(); 38 | private Variable z = new Variable(); 39 | 40 | @Test 41 | public void testTwoAtomsNotEqual() { 42 | Assert.assertNull(Unification.unify(new Unification.Atom(), new Unification.Atom())); 43 | } 44 | 45 | private Sequence seq(Unifiable... items) { 46 | return new Sequence(Arrays.asList(items)); 47 | } 48 | 49 | @Test 50 | public void testVariableResolvesTransitivelyToAtom() { 51 | // ? Y = [a, X], X = c. 52 | Substitution result = Unification.unify( 53 | seq(seq(a, x), b), 54 | seq(y, x)); 55 | // Y = [a, b], 56 | // X = b. 57 | Assert.assertEquals(seq(a, b), result.resolve(y)); 58 | Assert.assertEquals(b, result.resolve(x)); 59 | } 60 | 61 | @Test 62 | public void testSimpleAssignmentAcrossSequence() { 63 | Map expected = new HashMap<>(); 64 | expected.put(x, b); 65 | expected.put(y, a); 66 | Assert.assertEquals( 67 | expected, 68 | Unification.unify( 69 | seq(a, x), 70 | seq(y, b)).resultMap()); 71 | } 72 | 73 | @Test 74 | public void testGenericTypeLikeCase() { 75 | // a == a> 76 | // Y = c 77 | // Result: 78 | // Y = c 79 | // X = b 80 | Substitution result = Unification.unify( 81 | seq(seq(a, x ), y), 82 | seq(seq(a, seq(b, y)), c)); 83 | Assert.assertEquals(c, result.resolve(y)); 84 | Assert.assertEquals(seq(b, c), result.resolve(x)); 85 | } 86 | 87 | @Test 88 | public void testTrivialFailure() { 89 | Assert.assertNull(Unification.unify(seq(a), seq(b))); 90 | } 91 | 92 | @Test 93 | public void testSlighlyTrickyFailure() { 94 | Assert.assertNull(Unification.unify(seq(a, x, x, z), seq(y, b, z, y))); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/WithStyleTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Google, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package com.google.callbuilder; 15 | 16 | import com.google.callbuilder.style.ArrayListAdding; 17 | import com.google.callbuilder.style.StringAppending; 18 | 19 | import org.junit.Assert; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.junit.runners.JUnit4; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | 27 | @RunWith(JUnit4.class) 28 | public class WithStyleTest { 29 | static class TwoArrayLists { 30 | ArrayList first; 31 | ArrayList second; 32 | 33 | @CallBuilder 34 | TwoArrayLists( 35 | @BuilderField(style = ArrayListAdding.class) ArrayList first, 36 | @BuilderField(style = ArrayListAdding.class) ArrayList second) { 37 | this.first = first; 38 | this.second = second; 39 | } 40 | } 41 | 42 | static class HasStrings { 43 | String address; 44 | String name; 45 | 46 | @CallBuilder 47 | HasStrings( 48 | @BuilderField(style = StringAppending.class) String address, 49 | @BuilderField(style = StringAppending.class) String name) { 50 | this.address = address; 51 | this.name = name; 52 | } 53 | } 54 | 55 | @Test 56 | public void immutableListAddingFieldStyle() { 57 | TwoArrayLists lists = new TwoArrayListsBuilder() 58 | .addToFirst("one") 59 | .addToSecond(1) 60 | .addToFirst("DOS") 61 | .addToSecond(2) 62 | .addAllToFirst(Arrays.asList("san", "ourfay", "FIVE")) 63 | .addAllToSecond(Arrays.asList(3, 4, 5)) 64 | .build(); 65 | Assert.assertEquals( 66 | Arrays.asList("one", "DOS", "san", "ourfay", "FIVE"), 67 | lists.first); 68 | Assert.assertEquals( 69 | Arrays.asList(1, 2, 3, 4, 5), 70 | lists.second); 71 | } 72 | 73 | @Test 74 | public void stringAppendingFieldStyle() { 75 | HasStrings bothEmpty = new HasStringsBuilder() 76 | .build(); 77 | Assert.assertEquals("", bothEmpty.address); 78 | Assert.assertEquals("", bothEmpty.name); 79 | 80 | HasStrings addressOnly = new HasStringsBuilder() 81 | .appendToAddress("1212 Easy St.\n") 82 | .appendToAddress("Big Town, XY\n") 83 | .appendToAddress("42042\n") 84 | .build(); 85 | Assert.assertEquals("1212 Easy St.\nBig Town, XY\n42042\n", addressOnly.address); 86 | Assert.assertEquals("", addressOnly.name); 87 | 88 | HasStrings hasBoth = new HasStringsBuilder() 89 | .appendToName("Doe, ") 90 | .appendToAddress("1600 Amphitheatre Pkwy\n") 91 | .appendToName("John") 92 | .appendToAddress("Mountain View\n") 93 | .build(); 94 | Assert.assertEquals("Doe, John", hasBoth.name); 95 | Assert.assertEquals("1600 Amphitheatre Pkwy\nMountain View\n", hasBoth.address); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/util/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | package(default_testonly = 1) 16 | 17 | java_test( 18 | name = "ValueTypeTest", 19 | srcs = ["ValueTypeTest.java"], 20 | deps = [ 21 | "//java/com/google/callbuilder/util", 22 | "//third_party:junit4", 23 | ], 24 | ) -------------------------------------------------------------------------------- /javatests/com/google/callbuilder/util/ValueTypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.callbuilder.util; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertNotEquals; 20 | 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.junit.runners.JUnit4; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Arrays; 27 | import java.util.List; 28 | 29 | @RunWith(JUnit4.class) 30 | public class ValueTypeTest { 31 | private final class Empty extends ValueType { 32 | @Override 33 | protected void addFields(FieldReceiver fields) { } 34 | } 35 | 36 | private final class Name extends ValueType { 37 | private final String family; 38 | private final String given; 39 | 40 | Name(String family, String given) { 41 | this.family = family; 42 | this.given = given; 43 | } 44 | 45 | @Override 46 | protected void addFields(FieldReceiver fields) { 47 | fields.add("family", family); 48 | fields.add("given", given); 49 | } 50 | } 51 | 52 | private final class PairThatOmitsNull extends ValueType { 53 | private final Object first; 54 | private final Object second; 55 | 56 | PairThatOmitsNull(Object first, Object second) { 57 | this.first = first; 58 | this.second = second; 59 | } 60 | 61 | @Override 62 | protected void addFields(FieldReceiver fields) { 63 | if (first != null) { 64 | fields.add("first", first); 65 | } 66 | if (second != null) { 67 | fields.add("second", second); 68 | } 69 | } 70 | } 71 | 72 | @Test 73 | public void toString_noValues() { 74 | assertEquals("Empty{}", new Empty().toString()); 75 | } 76 | 77 | @Test 78 | public void toString_basic() { 79 | assertEquals("Name{family=Doe, given=John}", new Name("Doe", "John").toString()); 80 | } 81 | 82 | @Test 83 | public void toString_hasNull() { 84 | assertEquals("Name{family=Doe, given=null}", new Name("Doe", null).toString()); 85 | } 86 | 87 | private void assertMutuallyEqual(List equalityGroup) { 88 | for (int i = 1; i < equalityGroup.size(); i++) { 89 | assertEquals(equalityGroup.get(0), equalityGroup.get(i)); 90 | assertEquals(equalityGroup.get(i), equalityGroup.get(0)); 91 | assertEquals(equalityGroup.get(0).hashCode(), equalityGroup.get(i).hashCode()); 92 | assertEquals(equalityGroup.get(0).toString(), equalityGroup.get(i).toString()); 93 | } 94 | } 95 | 96 | private void assertMutuallyUnequal(List items) { 97 | for (int i = 0; i < items.size() - 1; i++) { 98 | for (int j = i + 1; j < items.size(); j++) { 99 | assertNotEquals(items.get(i), items.get(j)); 100 | assertNotEquals(items.get(j), items.get(i)); 101 | } 102 | } 103 | } 104 | 105 | @Test 106 | public void hashAndEquals() { 107 | List> equalityGroups = new ArrayList<>(); 108 | equalityGroups.add(Arrays.asList(new Empty(), new Empty())); 109 | equalityGroups.add(Arrays.asList(new Name("Foo", "Bar"), new Name("Foo", "Bar"))); 110 | equalityGroups.add(Arrays.asList(new Name("Foo", "NotBar"))); 111 | equalityGroups.add(Arrays.asList(new Name("NotFoo", "Bar"))); 112 | equalityGroups.add(Arrays.asList(new Name("Foo", null), new Name("Foo", null))); 113 | equalityGroups.add(Arrays.asList(new Name(null, "Bar"), new Name(null, "Bar"))); 114 | equalityGroups.add( 115 | Arrays.asList(new PairThatOmitsNull(null, 42), new PairThatOmitsNull(null, 42))); 116 | equalityGroups.add( 117 | Arrays.asList(new PairThatOmitsNull(42, null), new PairThatOmitsNull(42, null))); 118 | equalityGroups.add(Arrays.asList(new PairThatOmitsNull(42, 42), new PairThatOmitsNull(42, 42))); 119 | 120 | List distinctItems = new ArrayList<>(); 121 | for (List group : equalityGroups) { 122 | assertMutuallyEqual(group); 123 | distinctItems.add(group.get(0)); 124 | } 125 | 126 | assertMutuallyUnequal(distinctItems); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /third_party/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | package(default_visibility = ["//visibility:public"]) 16 | 17 | java_library( 18 | name = "junit4", 19 | exports = [ 20 | "@junit4//jar", 21 | ], 22 | ) 23 | -------------------------------------------------------------------------------- /third_party/jsr-305/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /third_party/jsr-305/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | JSR305-ri 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /third_party/jsr-305/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Wed Jun 20 13:34:34 GMT-05:00 2007 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.5 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.5 13 | -------------------------------------------------------------------------------- /third_party/jsr-305/.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | #Wed Jun 20 13:34:34 GMT-05:00 2007 2 | eclipse.preferences.version=1 3 | internal.default.compliance=default 4 | -------------------------------------------------------------------------------- /third_party/jsr-305/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | licenses(["notice"]) # BSD 4 | 5 | java_library( 6 | name = "jsr-305", 7 | srcs = glob(["**/*.java"]), 8 | ) 9 | -------------------------------------------------------------------------------- /third_party/jsr-305/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2009, JSR305 expert group 2 | All rights reserved. 3 | 4 | http://www.opensource.org/licenses/bsd-license.php 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of the JSR305 expert group nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /third_party/jsr-305/README.callbuilder: -------------------------------------------------------------------------------- 1 | URL: https://code.google.com/p/jsr-305/ 2 | Version: r51 3 | 4 | Notes: 5 | - Only includes the ri/ subfolder from the original repo. 6 | - Removed empty build/ folder so BUILD file could be created on case-insensitive 7 | file systems. 8 | -------------------------------------------------------------------------------- /third_party/jsr-305/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /third_party/jsr-305/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.ant.freeform 4 | 5 | 6 | JSR305-ri 7 | 8 | 9 | 10 | JSR305-ri 11 | 12 | 13 | 14 | 15 | java 16 | src/main/java 17 | UTF-8 18 | 19 | 20 | 21 | java 22 | src/main/resources 23 | UTF-8 24 | 25 | 26 | 27 | . 28 | UTF-8 29 | 30 | 31 | 32 | 33 | build 34 | 35 | 36 | clean 37 | 38 | 39 | clean 40 | build 41 | 42 | 43 | 44 | folder 45 | build 46 | build 47 | 48 | 49 | 50 | 51 | 52 | src/main/java 53 | 54 | 55 | 56 | src/main/resources 57 | 58 | 59 | build.xml 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | src/main/java 72 | src/main/resources 73 | build 74 | 1.5 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /third_party/jsr-305/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.jsr-305 8 | jsr-305 9 | 0.1-SNAPSHOT 10 | 11 | 12 | org.jsr-305 13 | ri 14 | jar 15 | JSR 305 Implementation 16 | 0.1-SNAPSHOT 17 | Implementation for JSR-305 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/CheckForNull.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifierNickname 12 | @Nonnull(when = When.MAYBE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface CheckForNull { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/CheckForSigned.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | /** 11 | * Used to annotate a value that may be either negative or nonnegative, and 12 | * indicates that uses of it should check for 13 | * negative values before using it in a way that requires the value to be 14 | * nonnegative, and check for it being nonnegative before using it in a way that 15 | * requires it to be negative. 16 | */ 17 | 18 | @Documented 19 | @TypeQualifierNickname 20 | @Nonnegative(when = When.MAYBE) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | public @interface CheckForSigned { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/CheckReturnValue.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.annotation.meta.When; 10 | 11 | @Documented 12 | @Target( { ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, 13 | ElementType.PACKAGE }) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface CheckReturnValue { 16 | When when() default When.ALWAYS; 17 | } 18 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Detainted.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifierNickname 12 | @Untainted(when = When.ALWAYS) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Detainted { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/MatchesPattern.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.util.regex.Pattern; 7 | 8 | import javax.annotation.meta.TypeQualifier; 9 | import javax.annotation.meta.TypeQualifierValidator; 10 | import javax.annotation.meta.When; 11 | 12 | @Documented 13 | @TypeQualifier(applicableTo = String.class) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface MatchesPattern { 16 | @RegEx 17 | String value(); 18 | 19 | int flags() default 0; 20 | 21 | static class Checker implements TypeQualifierValidator { 22 | public When forConstantValue(MatchesPattern annotation, Object value) { 23 | Pattern p = Pattern.compile(annotation.value(), annotation.flags()); 24 | if (p.matcher(((String) value)).matches()) 25 | return When.ALWAYS; 26 | return When.NEVER; 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Nonnegative.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifier; 8 | import javax.annotation.meta.TypeQualifierValidator; 9 | import javax.annotation.meta.When; 10 | 11 | /** Used to annotate a value that should only contain nonnegative values */ 12 | @Documented 13 | @TypeQualifier(applicableTo = Number.class) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Nonnegative { 16 | When when() default When.ALWAYS; 17 | 18 | class Checker implements TypeQualifierValidator { 19 | 20 | public When forConstantValue(Nonnegative annotation, Object v) { 21 | if (!(v instanceof Number)) 22 | return When.NEVER; 23 | boolean isNegative; 24 | Number value = (Number) v; 25 | if (value instanceof Long) 26 | isNegative = value.longValue() < 0; 27 | else if (value instanceof Double) 28 | isNegative = value.doubleValue() < 0; 29 | else if (value instanceof Float) 30 | isNegative = value.floatValue() < 0; 31 | else 32 | isNegative = value.intValue() < 0; 33 | 34 | if (isNegative) 35 | return When.NEVER; 36 | else 37 | return When.ALWAYS; 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Nonnull.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifier; 8 | import javax.annotation.meta.TypeQualifierValidator; 9 | import javax.annotation.meta.When; 10 | 11 | @Documented 12 | @TypeQualifier 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Nonnull { 15 | When when() default When.ALWAYS; 16 | 17 | static class Checker implements TypeQualifierValidator { 18 | 19 | public When forConstantValue(Nonnull qualifierqualifierArgument, 20 | Object value) { 21 | if (value == null) 22 | return When.NEVER; 23 | return When.ALWAYS; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Nullable.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifierNickname 12 | @Nonnull(when = When.UNKNOWN) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Nullable { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/OverridingMethodsMustInvokeSuper.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * When this annotation is applied to a method, it indicates that if this method 11 | * is overridden in a subclass, the overriding method should invoke this method 12 | * (through method invocation on super). 13 | * 14 | */ 15 | @Documented 16 | @Target( { ElementType.METHOD }) 17 | @Retention(RetentionPolicy.RUNTIME) 18 | public @interface OverridingMethodsMustInvokeSuper { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/ParametersAreNonnullByDefault.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | import javax.annotation.meta.TypeQualifierDefault; 9 | 10 | /** 11 | * This annotation can be applied to a package, class or method to indicate that 12 | * the method parameters in that element are nonnull by default unless there is: 13 | *
    14 | *
  • An explicit nullness annotation 15 | *
  • The method overrides a method in a superclass (in which case the 16 | * annotation of the corresponding parameter in the superclass applies) 17 | *
  • there is a default parameter annotation applied to a more tightly nested 18 | * element. 19 | *
20 | * 21 | */ 22 | @Documented 23 | @Nonnull 24 | @TypeQualifierDefault(ElementType.PARAMETER) 25 | @Retention(RetentionPolicy.RUNTIME) 26 | public @interface ParametersAreNonnullByDefault { 27 | } 28 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/ParametersAreNullableByDefault.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | import javax.annotation.meta.TypeQualifierDefault; 9 | 10 | /** 11 | * This annotation can be applied to a package, class or method to indicate that 12 | * the method parameters in that element are nullable by default unless there is: 13 | *
    14 | *
  • An explicit nullness annotation 15 | *
  • The method overrides a method in a superclass (in which case the 16 | * annotation of the corresponding parameter in the superclass applies) 17 | *
  • there is a default parameter annotation applied to a more tightly nested 18 | * element. 19 | *
20 | *

This annotation implies the same "nullness" as no annotation. However, it is different 21 | * than having no annotation, as it is inherited and it can override a ParametersAreNonnullByDefault 22 | * annotation at an outer scope. 23 | * 24 | */ 25 | @Documented 26 | @Nullable 27 | @TypeQualifierDefault(ElementType.PARAMETER) 28 | @Retention(RetentionPolicy.RUNTIME) 29 | public @interface ParametersAreNullableByDefault { 30 | } 31 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/PropertyKey.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifier; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifier 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface PropertyKey { 14 | When when() default When.ALWAYS; 15 | } 16 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/RegEx.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.util.regex.Pattern; 7 | import java.util.regex.PatternSyntaxException; 8 | 9 | import javax.annotation.meta.TypeQualifierNickname; 10 | import javax.annotation.meta.TypeQualifierValidator; 11 | import javax.annotation.meta.When; 12 | 13 | /** 14 | * This qualifier is used to denote String values that should be a Regular 15 | * expression. 16 | * 17 | */ 18 | @Documented 19 | @Syntax("RegEx") 20 | @TypeQualifierNickname 21 | @Retention(RetentionPolicy.RUNTIME) 22 | public @interface RegEx { 23 | When when() default When.ALWAYS; 24 | 25 | static class Checker implements TypeQualifierValidator { 26 | 27 | public When forConstantValue(RegEx annotation, Object value) { 28 | if (!(value instanceof String)) 29 | return When.NEVER; 30 | 31 | try { 32 | Pattern.compile((String) value); 33 | } catch (PatternSyntaxException e) { 34 | return When.NEVER; 35 | } 36 | return When.ALWAYS; 37 | 38 | } 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Signed.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | /** Used to annotate a value of unknown sign */ 11 | 12 | @Documented 13 | @TypeQualifierNickname 14 | @Nonnegative(when = When.UNKNOWN) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Signed { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Syntax.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifier; 8 | import javax.annotation.meta.When; 9 | 10 | /** 11 | * This annotation a value that is of a particular syntax, such as Java syntax 12 | * or regular expression syntax. This can be used to provide syntax checking of 13 | * constant values at compile time, run time checking at runtime, and can assist 14 | * IDEs in deciding how to interpret String constants (e.g., should a 15 | * refactoring that renames method x() to y() update the String constant "x()"). 16 | * 17 | * 18 | */ 19 | @Documented 20 | @TypeQualifier(applicableTo = CharSequence.class) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | public @interface Syntax { 23 | /** 24 | * Value indicating the particular syntax denoted by this annotation. 25 | * Different tools will recognize different syntaxes, but some proposed 26 | * canonical values are: 27 | *

    28 | *
  • "Java" 29 | *
  • "RegEx" 30 | *
  • "JavaScript" 31 | *
  • "Ruby" 32 | *
  • "Groovy" 33 | *
  • "SQL" 34 | *
  • "FormatString" 35 | *
36 | * 37 | * Syntax names can be followed by a colon and a list of key value pairs, 38 | * separated by commas. For example, "SQL:dialect=Oracle,version=2.3". Tools 39 | * should ignore any keys they don't recognize. 40 | */ 41 | String value(); 42 | 43 | When when() default When.ALWAYS; 44 | } 45 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Tainted.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifierNickname; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifierNickname 12 | @Untainted(when = When.MAYBE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Tainted { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/Untainted.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.annotation.meta.TypeQualifier; 8 | import javax.annotation.meta.When; 9 | 10 | @Documented 11 | @TypeQualifier 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface Untainted { 14 | When when() default When.ALWAYS; 15 | } 16 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/WillClose.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | @Documented 8 | @Retention(RetentionPolicy.RUNTIME) 9 | /** 10 | * Used to annotate a method parameter to indicate that this method will close 11 | * the resource. 12 | */ 13 | public @interface WillClose { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/WillCloseWhenClosed.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | @Documented 8 | @Retention(RetentionPolicy.RUNTIME) 9 | /** 10 | * Used to annotate a constructor/factory parameter to indicate that returned 11 | * object (X) will close the resource when X is closed. 12 | */ 13 | public @interface WillCloseWhenClosed { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/WillNotClose.java: -------------------------------------------------------------------------------- 1 | package javax.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | @Documented 8 | @Retention(RetentionPolicy.RUNTIME) 9 | /** 10 | * Used to annotate a method parameter to indicate that this method will not 11 | * close the resource. 12 | */ 13 | public @interface WillNotClose { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/concurrent/GuardedBy.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.concurrent; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /* 9 | * Copyright (c) 2005 Brian Goetz 10 | * Released under the Creative Commons Attribution License 11 | * (http://creativecommons.org/licenses/by/2.5) 12 | * Official home: http://www.jcip.net 13 | */ 14 | 15 | /** 16 | * GuardedBy 17 | * 18 | * The field or method to which this annotation is applied can only be accessed 19 | * when holding a particular lock, which may be a built-in (synchronization) 20 | * lock, or may be an explicit java.util.concurrent.Lock. 21 | * 22 | * The argument determines which lock guards the annotated field or method: this : 23 | * The string literal "this" means that this field is guarded by the class in 24 | * which it is defined. class-name.this : For inner classes, it may be necessary 25 | * to disambiguate 'this'; the class-name.this designation allows you to specify 26 | * which 'this' reference is intended itself : For reference fields only; the 27 | * object to which the field refers. field-name : The lock object is referenced 28 | * by the (instance or static) field specified by field-name. 29 | * class-name.field-name : The lock object is reference by the static field 30 | * specified by class-name.field-name. method-name() : The lock object is 31 | * returned by calling the named nil-ary method. class-name.class : The Class 32 | * object for the specified class should be used as the lock object. 33 | */ 34 | @Target( { ElementType.FIELD, ElementType.METHOD }) 35 | @Retention(RetentionPolicy.CLASS) 36 | public @interface GuardedBy { 37 | String value(); 38 | } 39 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/concurrent/Immutable.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.concurrent; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /* 10 | * Copyright (c) 2005 Brian Goetz 11 | * Released under the Creative Commons Attribution License 12 | * (http://creativecommons.org/licenses/by/2.5) 13 | * Official home: http://www.jcip.net 14 | */ 15 | 16 | /** 17 | * Immutable 18 | * 19 | * The class to which this annotation is applied is immutable. This means that 20 | * its state cannot be seen to change by callers. Of necessity this means that 21 | * all public fields are final, and that all public final reference fields refer 22 | * to other immutable objects, and that methods do not publish references to any 23 | * internal state which is mutable by implementation even if not by design. 24 | * Immutable objects may still have internal mutable state for purposes of 25 | * performance optimization; some state variables may be lazily computed, so 26 | * long as they are computed from immutable state and that callers cannot tell 27 | * the difference. 28 | * 29 | * Immutable objects are inherently thread-safe; they may be passed between 30 | * threads or published without synchronization. 31 | */ 32 | @Documented 33 | @Target(ElementType.TYPE) 34 | @Retention(RetentionPolicy.CLASS) 35 | public @interface Immutable { 36 | } 37 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/concurrent/NotThreadSafe.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.concurrent; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /* 10 | * Copyright (c) 2005 Brian Goetz 11 | * Released under the Creative Commons Attribution License 12 | * (http://creativecommons.org/licenses/by/2.5) 13 | * Official home: http://www.jcip.net 14 | */ 15 | 16 | /** 17 | * NotThreadSafe 18 | * 19 | * The class to which this annotation is applied is not thread-safe. This 20 | * annotation primarily exists for clarifying the non-thread-safety of a class 21 | * that might otherwise be assumed to be thread-safe, despite the fact that it 22 | * is a bad idea to assume a class is thread-safe without good reason. 23 | * 24 | * @see ThreadSafe 25 | */ 26 | @Documented 27 | @Target(ElementType.TYPE) 28 | @Retention(RetentionPolicy.CLASS) 29 | public @interface NotThreadSafe { 30 | } 31 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/concurrent/ThreadSafe.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.concurrent; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * ThreadSafe 11 | * 12 | * The class to which this annotation is applied is thread-safe. This means that 13 | * no sequences of accesses (reads and writes to public fields, calls to public 14 | * methods) may put the object into an invalid state, regardless of the 15 | * interleaving of those actions by the runtime, and without requiring any 16 | * additional synchronization or coordination on the part of the caller. 17 | */ 18 | @Documented 19 | @Target(ElementType.TYPE) 20 | @Retention(RetentionPolicy.CLASS) 21 | public @interface ThreadSafe { 22 | } 23 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/Exclusive.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | /** 8 | * This annotation can be applied to the value() element of an annotation that 9 | * is annotated as a TypeQualifier. 10 | * 11 | * For example, the following defines a type qualifier such that if you know a 12 | * value is {@literal @Foo(1)}, then the value cannot be {@literal @Foo(2)} or {{@literal @Foo(3)}. 13 | * 14 | * 15 | * @TypeQualifier @interface Foo { 16 | * @Exclusive int value(); 17 | * } 18 | * 19 | * 20 | */ 21 | 22 | @Documented 23 | @Retention(RetentionPolicy.RUNTIME) 24 | public @interface Exclusive { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/Exhaustive.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | /** 8 | * This annotation can be applied to the value() element of an annotation that 9 | * is annotated as a TypeQualifier. This is only appropriate if the value field 10 | * returns a value that is an Enumeration. 11 | * 12 | * Applications of the type qualifier with different values are exclusive, and 13 | * the enumeration is an exhaustive list of the possible values. 14 | * 15 | * For example, the following defines a type qualifier such that if you know a 16 | * value is neither {@literal @Foo(Color.Red)} or {@literal @Foo(Color.Blue)}, 17 | * then the value must be {@literal @Foo(Color.Green)}. And if you know it is 18 | * {@literal @Foo(Color.Green)}, you know it cannot be 19 | * {@literal @Foo(Color.Red)} or {@literal @Foo(Color.Blue)} 20 | * 21 | * 22 | * @TypeQualifier @interface Foo { 23 | * enum Color {RED, BLUE, GREEN}; 24 | * @Exhaustive Color value(); 25 | * } 26 | * 27 | */ 28 | 29 | @Documented 30 | @Retention(RetentionPolicy.RUNTIME) 31 | public @interface Exhaustive { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/TypeQualifier.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * This qualifier is applied to an annotation to denote that the annotation 11 | * should be treated as a type qualifier. 12 | */ 13 | 14 | @Documented 15 | @Target(ElementType.ANNOTATION_TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface TypeQualifier { 18 | 19 | /** 20 | * Describes the kinds of values the qualifier can be applied to. If a 21 | * numeric class is provided (e.g., Number.class or Integer.class) then the 22 | * annotation can also be applied to the corresponding primitive numeric 23 | * types. 24 | */ 25 | Class applicableTo() default Object.class; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/TypeQualifierDefault.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * This qualifier is applied to an annotation to denote that the annotation 11 | * defines a default type qualifier that is visible within the scope of the 12 | * element it is applied to. 13 | */ 14 | 15 | @Documented 16 | @Target(ElementType.ANNOTATION_TYPE) 17 | @Retention(RetentionPolicy.RUNTIME) 18 | public @interface TypeQualifierDefault { 19 | ElementType[] value() default {}; 20 | } 21 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/TypeQualifierNickname.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Target; 6 | 7 | /** 8 | * 9 | * This annotation is applied to a annotation, and marks the annotation as being 10 | * a qualifier nickname. Applying a nickname annotation X to a element Y should 11 | * be interpreted as having the same meaning as applying all of annotations of X 12 | * (other than QualifierNickname) to Y. 13 | * 14 | *

15 | * Thus, you might define a qualifier SocialSecurityNumber as follows: 16 | *

17 | * 18 | * 19 | * 20 | @Documented 21 | @TypeQualifierNickname @Pattern("[0-9]{3}-[0-9]{2}-[0-9]{4}") 22 | @Retention(RetentionPolicy.RUNTIME) 23 | public @interface SocialSecurityNumber { 24 | } 25 | 26 | * 27 | * 28 | */ 29 | @Documented 30 | @Target(ElementType.ANNOTATION_TYPE) 31 | public @interface TypeQualifierNickname { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/TypeQualifierValidator.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | import java.lang.annotation.Annotation; 4 | 5 | import javax.annotation.Nonnull; 6 | 7 | public interface TypeQualifierValidator { 8 | /** 9 | * Given a type qualifier, check to see if a known specific constant value 10 | * is an instance of the set of values denoted by the qualifier. 11 | * 12 | * @param annotation 13 | * the type qualifier 14 | * @param value 15 | * the value to check 16 | * @return a value indicating whether or not the value is an member of the 17 | * values denoted by the type qualifier 18 | */ 19 | public @Nonnull 20 | When forConstantValue(@Nonnull A annotation, Object value); 21 | } 22 | -------------------------------------------------------------------------------- /third_party/jsr-305/src/main/java/javax/annotation/meta/When.java: -------------------------------------------------------------------------------- 1 | package javax.annotation.meta; 2 | 3 | /** 4 | * Used to describe the relationship between a qualifier T and the set of values 5 | * S possible on an annotated element. 6 | * 7 | * In particular, an issues should be reported if an ALWAYS or MAYBE value is 8 | * used where a NEVER value is required, or if a NEVER or MAYBE value is used 9 | * where an ALWAYS value is required. 10 | * 11 | * 12 | */ 13 | public enum When { 14 | /** S is a subset of T */ 15 | ALWAYS, 16 | /** nothing definitive is known about the relation between S and T */ 17 | UNKNOWN, 18 | /** S intersection T is non empty and S - T is nonempty */ 19 | MAYBE, 20 | /** S intersection T is empty */ 21 | NEVER; 22 | 23 | } 24 | --------------------------------------------------------------------------------