├── android ├── .gitignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── lint-baseline.xml ├── lint.xml ├── settings.gradle ├── AndroidManifest.xml ├── gradle.properties ├── build.gradle └── gradlew.bat ├── java-8 ├── .gitignore ├── gradle.properties ├── settings.gradle └── build.gradle ├── .release-please-manifest.json ├── .github ├── CODEOWNERS ├── release-please.yml ├── ISSUE_TEMPLATE │ ├── 03-blank-issue.md │ ├── config.yml │ ├── 02-sdk-feature-request.yml │ └── 01-sdk-bug.yml ├── workflows │ ├── auto-merge-dependabot.yml │ ├── api-level-lint.yml │ ├── gradle-build.yml │ ├── release-please-gha.yml │ ├── conflicting-pr-label.yml │ ├── sonarcloud.yml │ ├── codeql-analysis.yml │ └── project-auto-add.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── policies │ ├── resourceManagement.yml │ └── msgraph-sdk-java-core-branch-protection.yml ├── .vscode └── settings.json ├── .editorconfig ├── devx.yml ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── dependencies.gradle ├── settings.gradle ├── src ├── main │ └── java │ │ └── com │ │ └── microsoft │ │ └── graph │ │ └── core │ │ ├── models │ │ ├── IProgressCallback.java │ │ ├── EncryptedContentBearer.java │ │ ├── UploadResult.java │ │ ├── EncryptableSubscription.java │ │ ├── DiscoverUrlAdapter.java │ │ ├── IUploadSession.java │ │ └── BatchRequestStep.java │ │ ├── exceptions │ │ └── ClientException.java │ │ ├── requests │ │ ├── IBaseClient.java │ │ ├── FeatureTracker.java │ │ ├── FeatureFlag.java │ │ ├── upload │ │ │ ├── UploadSessionRequestBuilder.java │ │ │ ├── UploadSliceRequestBuilder.java │ │ │ └── UploadResponseHandler.java │ │ ├── options │ │ │ └── GraphClientOption.java │ │ ├── BatchRequestBuilder.java │ │ ├── middleware │ │ │ └── GraphTelemetryHandler.java │ │ └── ResponseBodyHandler.java │ │ ├── content │ │ ├── KeyedBatchResponseContent.java │ │ └── BatchResponseContentCollection.java │ │ ├── tasks │ │ └── PageIteratorBuilder.java │ │ └── authentication │ │ ├── AzureIdentityAuthenticationProvider.java │ │ └── AzureIdentityAccessTokenProvider.java └── test │ └── java │ └── com │ └── microsoft │ └── graph │ └── core │ ├── requests │ ├── upload │ │ ├── UploadSessionTest.java │ │ └── UploadSliceRequestTest.java │ ├── FeatureTrackerTest.java │ ├── MockResponseHandler.java │ ├── BatchRequestBuilderTest.java │ └── middleware │ │ └── GraphTelemetryHandlerTest.java │ ├── testModels │ ├── TestBodyType.java │ ├── TestChangeType.java │ ├── TestLifecycleEventType.java │ ├── TestAttendee.java │ ├── TestEventsResponse.java │ ├── TestChatMessage.java │ ├── TestEventsDeltaResponse.java │ ├── TestDrive.java │ ├── TestDriveItem.java │ ├── TestNoteBook.java │ ├── TestEmailAddress.java │ ├── TestRecipient.java │ ├── TestDateTimeTimeZone.java │ ├── TestItemBody.java │ ├── BaseCollectionPaginationCountResponse.java │ ├── TestEvent.java │ ├── TestUser.java │ └── TestResourceData.java │ ├── BaseClient.java │ └── models │ └── TokenValidableTests.java ├── .gitignore ├── CODE_OF_CONDUCT.md ├── release-please-config.json ├── LICENSE ├── scripts ├── decodeAndWrite.ps1 ├── getLatestVersion.ps1 └── validatePackageContents.ps1 ├── THIRD PARTY NOTICES ├── gradle.properties ├── pom.xml ├── SECURITY.md ├── gradlew.bat ├── CONTRIBUTING.md ├── spotBugsExcludeFilter.xml └── README.md /android/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build -------------------------------------------------------------------------------- /java-8/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "3.6.5" 3 | } 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @microsoftgraph/msgraph-devx-java-write 2 | -------------------------------------------------------------------------------- /java-8/gradle.properties: -------------------------------------------------------------------------------- 1 | mavenArtifactId = msgraph-sdk-java-core 2 | -------------------------------------------------------------------------------- /java-8/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'msgraph-sdk-java-core' 2 | -------------------------------------------------------------------------------- /.github/release-please.yml: -------------------------------------------------------------------------------- 1 | manifest: true 2 | primaryBranch: main 3 | handleGHRelease: true 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.java] 2 | indent_style = space 3 | indent_size = 4 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /devx.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | - java 3 | extensions: 4 | services: 5 | - Microsoft Graph 6 | dependencyFile: /gradle/dependencies.gradle 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-java-core/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-java-core/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03-blank-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Blank issue 3 | about: Something that doesn't fit the other categories 4 | title: '' 5 | labels: ["status:waiting-for-triage"] 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /android/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.6/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'msgraph-sdk-java-core' 11 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.6/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'msgraph-sdk-java-core' 11 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/IProgressCallback.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | /** 4 | * Defines how to return progress status from a request. 5 | */ 6 | @FunctionalInterface 7 | public interface IProgressCallback { 8 | 9 | /** 10 | * How progress updates are handled for this callback 11 | * 12 | * @param current the current amount of progress 13 | * @param max the max amount of progress 14 | */ 15 | void report(final long current, final long max); 16 | } 17 | -------------------------------------------------------------------------------- /java-8/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | // Apply the java-library plugin to add support for Java Library 3 | id 'java-library' 4 | id 'eclipse' 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | sourceSets { 12 | main { 13 | java { 14 | srcDirs = ['../src'] 15 | exclude 'test/**' 16 | } 17 | } 18 | } 19 | 20 | java { 21 | toolchain { 22 | languageVersion = JavaLanguageVersion.of(8) 23 | } 24 | withSourcesJar() 25 | } 26 | 27 | apply from: "../gradle/dependencies.gradle" 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | /.gradle/ 24 | /build/ 25 | /bin/ 26 | 27 | #Eclipse 28 | .project 29 | .classpath 30 | .settings 31 | 32 | # IntelliJ 33 | *.iml 34 | .idea/ 35 | 36 | # Maven 37 | /target/ 38 | local.properties 39 | *.gpg 40 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | - Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support) 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Question on use of graph sdk 4 | url: https://github.com/microsoftgraph/msgraph-sdk-java/discussions 5 | about: Please add your question in the discussions section of the repo 6 | - name: Question on use of kiota 7 | url: https://github.com/microsoft/kiota/discussions 8 | about: Please add your question in the discussions section of the repo 9 | - name: Question or Feature Request for the MS Graph API? 10 | url: https://aka.ms/msgraphsupport 11 | about: Report an issue or limitation with the MS Graph service APIs 12 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/EncryptedContentBearer.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | /** 4 | * Contains Decryptable content 5 | * @param The type of the decryptable content 6 | */ 7 | public interface EncryptedContentBearer { 8 | 9 | /** 10 | * Sets encrypted content 11 | * @param encryptedContent encrypted content 12 | */ 13 | public void setEncryptedContent(T encryptedContent); 14 | 15 | /** 16 | * Return encrypted content 17 | * @return encrypted content 18 | */ 19 | public T getEncryptedContent(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/upload/UploadSessionTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.upload; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertNull; 4 | 5 | import java.util.List; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import com.microsoft.graph.core.models.UploadSession; 10 | 11 | class UploadSessionTest { 12 | @Test 13 | void getNextExpectedRangesDoesNotFailOnDefault() 14 | { 15 | final UploadSession uploadSession = new UploadSession(); 16 | final List result = uploadSession.getNextExpectedRanges(); 17 | assertNull(result); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/exceptions/ClientException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.exceptions; 2 | 3 | import jakarta.annotation.Nonnull; 4 | 5 | /** 6 | * Graph client exception wrapper. 7 | */ 8 | public class ClientException extends Exception { 9 | /** 10 | * Constructor for a ClientException 11 | * @param message The exception message. 12 | * @param cause The possible inner exception causing this exception. 13 | */ 14 | public ClientException(@Nonnull String message, @Nonnull Throwable cause) { 15 | super(message, cause); 16 | } 17 | /*** 18 | * Constructor for a ClientException 19 | * @param message The exception message. 20 | */ 21 | public ClientException(@Nonnull String message) { 22 | super(message); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/IBaseClient.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import com.microsoft.kiota.RequestAdapter; 4 | 5 | import jakarta.annotation.Nonnull; 6 | 7 | /** 8 | * The default client interface 9 | */ 10 | public interface IBaseClient { 11 | /** 12 | * Method to set the RequestAdapter property 13 | * @param requestAdapter specifies the desired RequestAdapter 14 | */ 15 | void setRequestAdapter(@Nonnull RequestAdapter requestAdapter); 16 | /** 17 | * Returns the current RequestAdapter for sending requests 18 | * @return the RequestAdapter currently in use 19 | */ 20 | @Nonnull 21 | RequestAdapter getRequestAdapter(); 22 | /** 23 | * Gets the BatchRequestBuilder 24 | * @return the BatchRequestBuilder instance 25 | */ 26 | @Nonnull 27 | BatchRequestBuilder getBatchRequestBuilder(); 28 | } 29 | -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /.github/workflows/auto-merge-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Auto-merge dependabot updates 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | permissions: 8 | pull-requests: write 9 | contents: write 10 | 11 | jobs: 12 | 13 | dependabot-merge: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | if: ${{ github.actor == 'dependabot[bot]' }} 18 | 19 | steps: 20 | - name: Dependabot metadata 21 | id: metadata 22 | uses: dependabot/fetch-metadata@v2.4.0 23 | with: 24 | github-token: "${{ secrets.GITHUB_TOKEN }}" 25 | 26 | - name: Enable auto-merge for Dependabot PRs 27 | # Only if version bump is not a major version change 28 | if: ${{steps.metadata.outputs.update-type != 'version-update:semver-major'}} 29 | run: gh pr merge --auto --merge "$PR_URL" 30 | env: 31 | PR_URL: ${{github.event.pull_request.html_url}} 32 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 33 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootstrap-sha": "e4d7342b47cc665d8137b046ed985bf7b7d76441", 3 | "exclude-paths": [ 4 | ".git", 5 | ".idea", 6 | ".github", 7 | ".vscode" 8 | ], 9 | "release-type": "simple", 10 | "include-component-in-tag": false, 11 | "include-v-in-tag": true, 12 | "packages": { 13 | ".": { 14 | "package-name": "com.microsoft.graph.microsoft-graph-core", 15 | "changelog-path": "CHANGELOG.md", 16 | "extra-files": [ 17 | "gradle.properties", 18 | "README.md", 19 | "src/main/java/com/microsoft/graph/core/CoreConstants.java", 20 | { 21 | "type": "xml", 22 | "path": "pom.xml", 23 | "xpath": "//project/version" 24 | } 25 | ] 26 | } 27 | }, 28 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" 29 | } 30 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | Fixes # 12 | 13 | 14 | ### Changes proposed in this pull request 15 | - 16 | 17 | 18 | ### Other links 19 | - 20 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestBodyType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.ValuedEnum; 4 | import jakarta.annotation.Nonnull; 5 | import jakarta.annotation.Nullable; 6 | 7 | import java.util.Objects; 8 | 9 | public enum TestBodyType implements ValuedEnum { 10 | Text("Text"), 11 | Html("Html"); 12 | public final String value; 13 | 14 | TestBodyType(@Nonnull final String value) { 15 | this.value = value; 16 | } 17 | 18 | @Nonnull 19 | @Override 20 | public String getValue() { 21 | return this.value; 22 | } 23 | 24 | @Nullable public static TestBodyType forValue(@Nullable final String searchValue) { 25 | Objects.requireNonNull(searchValue); 26 | switch(searchValue) { 27 | case "Text": return Text; 28 | case "Html": return Html; 29 | default: return null; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestChangeType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.ValuedEnum; 4 | import java.util.Objects; 5 | 6 | public enum TestChangeType implements ValuedEnum { 7 | Created("created"), 8 | Updated("updated"), 9 | Deleted("deleted"); 10 | public final String value; 11 | TestChangeType(final String value) { 12 | this.value = value; 13 | } 14 | @jakarta.annotation.Nonnull 15 | public String getValue() { return this.value; } 16 | @jakarta.annotation.Nullable 17 | public static TestChangeType forValue(@jakarta.annotation.Nonnull final String searchValue) { 18 | Objects.requireNonNull(searchValue); 19 | switch(searchValue) { 20 | case "created": return Created; 21 | case "updated": return Updated; 22 | case "deleted": return Deleted; 23 | default: return null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/FeatureTrackerTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | class FeatureTrackerTest { 8 | @Test 9 | void setFeatureUsageTest() { 10 | FeatureTracker featureTracker = new FeatureTracker(); 11 | featureTracker.setFeatureUsage(FeatureFlag.AUTH_HANDLER_FLAG); 12 | featureTracker.setFeatureUsage(FeatureFlag.REDIRECT_HANDLER_FLAG); 13 | assertEquals("5", featureTracker.getSerializedFeatureUsage()); 14 | } 15 | @Test 16 | void getSerializedFeatureUsageTest() { 17 | FeatureTracker featureTracker = new FeatureTracker(); 18 | featureTracker.setFeatureUsage(FeatureFlag.AUTH_HANDLER_FLAG); 19 | featureTracker.setFeatureUsage(FeatureFlag.REDIRECT_HANDLER_FLAG); 20 | featureTracker.setFeatureUsage(FeatureFlag.RETRY_HANDLER_FLAG); 21 | assertEquals("7", featureTracker.getSerializedFeatureUsage()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/content/KeyedBatchResponseContent.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.content; 2 | 3 | import jakarta.annotation.Nonnull; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | /** 8 | * A model to map id Keys to requests within a BatchResponseContent object. 9 | */ 10 | public class KeyedBatchResponseContent { 11 | /** 12 | * The ids of the requests that were batched together. 13 | */ 14 | @Nonnull 15 | protected HashSet keys; 16 | /** 17 | * The BatchResponseContent object paired to the keys. 18 | */ 19 | @Nonnull 20 | protected BatchResponseContent response; 21 | /** 22 | * Instantiates a new Keyed batch response content. 23 | * @param keys the ids of the requests that were batched together. 24 | * @param response the BatchResponseContent object to add to the collection. 25 | */ 26 | public KeyedBatchResponseContent(@Nonnull Set keys, @Nonnull BatchResponseContent response) { 27 | this.keys = new HashSet<>(keys); 28 | this.response = response; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestLifecycleEventType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.ValuedEnum; 4 | import java.util.Objects; 5 | 6 | public enum TestLifecycleEventType implements ValuedEnum { 7 | Missed("missed"), 8 | SubscriptionRemoved("subscriptionRemoved"), 9 | ReauthorizationRequired("reauthorizationRequired"); 10 | public final String value; 11 | TestLifecycleEventType(final String value) { 12 | this.value = value; 13 | } 14 | @jakarta.annotation.Nonnull 15 | public String getValue() { return this.value; } 16 | @jakarta.annotation.Nullable 17 | public static TestLifecycleEventType forValue(@jakarta.annotation.Nonnull final String searchValue) { 18 | Objects.requireNonNull(searchValue); 19 | switch(searchValue) { 20 | case "missed": return Missed; 21 | case "subscriptionRemoved": return SubscriptionRemoved; 22 | case "reauthorizationRequired": return ReauthorizationRequired; 23 | default: return null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Microsoft Graph 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/UploadResult.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import jakarta.annotation.Nullable; 4 | 5 | import java.net.URI; 6 | 7 | /** 8 | * Model containing the information from an upload response. 9 | * @param The type of item contained in the response. 10 | */ 11 | public class UploadResult { 12 | /** 13 | * Default constructor. 14 | */ 15 | public UploadResult() { 16 | //Default constructor 17 | } 18 | /** The UploadSession containing information about the created upload session. */ 19 | @Nullable 20 | public IUploadSession uploadSession; 21 | /** The uploaded item, once upload has completed. */ 22 | @Nullable 23 | public T itemResponse; 24 | /** The uploaded item location, once upload has completed. */ 25 | @Nullable 26 | public URI location; 27 | /** 28 | * Status of the request. 29 | * @return A boolean dictating whether the upload has been fully completed. 30 | */ 31 | public boolean isUploadSuccessful() { 32 | return (this.itemResponse != null) || (this.location != null); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/api-level-lint.yml: -------------------------------------------------------------------------------- 1 | name: "Checks the SDK only using APIs from the targeted API level" 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [main, support/2.x.x] 7 | pull_request: 8 | branches: [main, support/2.x.x] 9 | 10 | jobs: 11 | lint-api-level: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v5 15 | - uses: actions/setup-java@v5 16 | with: 17 | distribution: 'temurin' 18 | java-version: 21 19 | cache: gradle 20 | - name: Setup Android SDK 21 | uses: android-actions/setup-android@v3.2.2 22 | - name: Add execution right to the script 23 | run: chmod +x gradlew 24 | working-directory: ./android 25 | - name: Build SDK with Android project configuration 26 | id: lint 27 | run: ./gradlew --no-daemon build 28 | working-directory: ./android 29 | - name: Upload linting results 30 | if: failure() && steps.lint.outcome == 'failure' 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: lint-report 34 | path: ./android/build/reports 35 | 36 | -------------------------------------------------------------------------------- /scripts/decodeAndWrite.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT License. 3 | 4 | <# 5 | .Synopsis 6 | Decode the encoded string and write it to a local file. 7 | .Description 8 | Recieves an encoded string value and decodes it using base64. 9 | Write the new decoded string to a local file for later consumption. 10 | .Parameter encodedValue 11 | The encoded string we wish to decode. 12 | .Parameter outputPath 13 | The file path that we wish to write the decoded value to. 14 | #> 15 | 16 | Param( 17 | [string]$encodedValue , 18 | [string]$outputPath 19 | ) 20 | 21 | if($outputPath -eq "" -or $null -eq $outputPath) { 22 | Write-Output "Value of Variable: outputPath is Null or Empty. Exiting." 23 | Exit 24 | } 25 | if($encodedValue -eq "" -or $null -eq $encodedValue) { 26 | Write-Output "Value of Variable: encodedValue is Null of Empty. Exiting." 27 | Exit 28 | } 29 | 30 | $decodedValue = [System.Convert]::FromBase64String($encodedValue) 31 | $targetFullPath = Join-Path $PWD -ChildPath $outputPath 32 | [System.IO.File]::WriteAllBytes($targetFullPath, $decodedValue) 33 | -------------------------------------------------------------------------------- /.github/workflows/gradle-build.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Gradle 2 | 3 | on: 4 | pull_request: 5 | branches: [main, support/2.x.x] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v5 13 | - name: Set up JDK 14 | uses: actions/setup-java@v5 15 | with: 16 | java-version: 21 17 | distribution: 'temurin' 18 | cache: gradle 19 | - name: Grant execute permission for gradlew 20 | run: chmod +x gradlew 21 | - name: Build with Gradle 22 | run: ./gradlew build 23 | - name: Build with Java 8 24 | working-directory: ./java-8 25 | run: .././gradlew build 26 | - name: Upload a Build Artifact 27 | uses: actions/upload-artifact@v4 28 | with: 29 | name: drop 30 | path: | 31 | **/libs/* 32 | build/generated-pom.xml 33 | build/generated-pom.xml.asc 34 | build.gradle 35 | gradlew 36 | gradlew.bat 37 | settings.gradle 38 | gradle.properties 39 | **/gradle/** 40 | Scripts/** 41 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestAttendee.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.Map; 10 | 11 | public class TestAttendee extends TestRecipient implements Parsable, AdditionalDataHolder { 12 | public TestAttendee() { 13 | this.ODataType = "microsoft.graph.attendee"; 14 | } 15 | 16 | @Override 17 | public void serialize(@Nonnull SerializationWriter writer) { 18 | super.serialize(writer); 19 | writer.writeAdditionalData(this.additionalData); 20 | } 21 | 22 | public static TestAttendee createFromDiscriminatorValue(ParseNode parseNode) { 23 | if (parseNode == null) { 24 | throw new IllegalArgumentException("The parseNode parameter cannot be null."); 25 | } 26 | return new TestAttendee(); 27 | } 28 | 29 | @Nonnull 30 | @Override 31 | public Map getAdditionalData() { 32 | return this.additionalData; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02-sdk-feature-request.yml: -------------------------------------------------------------------------------- 1 | name: SDK Feature request 2 | description: Request a new feature on the SDK 3 | labels: ["type:feature", "status:waiting-for-triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | **Thank you for taking the time to fill out this feature request form!** 9 | 💥Please search to see if an issue already exists for the feature you are requesting. 10 | - type: textarea 11 | attributes: 12 | label: Is your feature request related to a problem? Please describe the problem. 13 | description: A clear and concise description of what the problem is. 14 | placeholder: I am trying to do [...] but [...] 15 | validations: 16 | required: false 17 | - type: textarea 18 | attributes: 19 | label: Describe the solution you'd like. 20 | description: | 21 | A clear and concise description of what you want to happen. Include any alternative solutions you've considered. 22 | validations: 23 | required: true 24 | - type: textarea 25 | attributes: 26 | label: Additional context? 27 | description: | 28 | Add any other context or screenshots about the feature request here. 29 | validations: 30 | required: false 31 | -------------------------------------------------------------------------------- /THIRD PARTY NOTICES: -------------------------------------------------------------------------------- 1 | This file is based on or incorporates material from the projects listed below 2 | (Third Party IP). The original copyright notice and the license under which 3 | Microsoft received such Third Party IP, are set forth below. Such licenses and 4 | notices are provided for informational purposes only. Microsoft licenses the 5 | Third Party IP to you under the licensing terms for the Microsoft product. 6 | Microsoft reserves all other rights not expressly granted under this agreement, 7 | whether by implication, estoppel or otherwise. 8 | 9 | Gson 10 | Copyright 2008-2011 Google Inc. 11 | 12 | Provided for Informational Purposes Only 13 | 14 | Apache 2.0 License 15 | 16 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 17 | this file except in compliance with the License. You may obtain a copy of the 18 | License at http://www.apache.org/licenses/LICENSE-2.0 19 | 20 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 21 | ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 22 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 23 | MERCHANTABLITY OR NON-INFRINGEMENT. 24 | 25 | See the Apache Version 2.0 License for specific language governing permissions 26 | and limitations under the License. -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/FeatureTracker.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | 4 | import jakarta.annotation.Nonnull; 5 | 6 | /** 7 | * Manages and tracks the flags for tasks and handlers. 8 | */ 9 | public class FeatureTracker { 10 | /** 11 | * Default constructor 12 | */ 13 | public FeatureTracker() { 14 | //Default constructor 15 | } 16 | 17 | private int featureUsage = FeatureFlag.NONE_FLAG; 18 | /** 19 | * Sets a numeric representation of the SDK feature usage 20 | * @param flag a numeric representation of the SDK feature usage 21 | */ 22 | public void setFeatureUsage(@Nonnull int flag) { 23 | 24 | featureUsage = featureUsage | flag; 25 | } 26 | /** 27 | * Gets a numeric representation of the SDK feature usage 28 | * @return a numeric representation of the SDK feature usage 29 | */ 30 | public int getFeatureUsage() { 31 | return featureUsage; 32 | } 33 | 34 | /** 35 | * Gets a serialized representation of the SDK feature usage. 36 | * @return a serialized representation of the SDK feature usage 37 | */ 38 | @Nonnull 39 | public String getSerializedFeatureUsage() { 40 | return Integer.toHexString(featureUsage); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directories: 5 | - "/" 6 | - "/java-8" 7 | schedule: 8 | interval: daily 9 | time: "09:00" # 9am UTC 10 | open-pull-requests-limit: 10 11 | groups: 12 | kiota-dependencies: 13 | patterns: 14 | - "*kiota*" 15 | junit-dependencies: 16 | patterns: 17 | - "*junit*" 18 | open-telemetry: 19 | patterns: 20 | - "*opentelemetry*" 21 | - package-ecosystem: gradle 22 | directory: "/android" 23 | schedule: 24 | interval: daily 25 | time: "10:00" # 10am UTC. After core dependencies are updated to prevent duplicates. 26 | open-pull-requests-limit: 10 27 | groups: 28 | kiota-dependencies: 29 | patterns: 30 | - "*kiota*" 31 | junit-dependencies: 32 | patterns: 33 | - "*junit*" 34 | open-telemetry: 35 | patterns: 36 | - "*opentelemetry*" 37 | - package-ecosystem: maven 38 | directory: "/" 39 | schedule: 40 | interval: daily 41 | open-pull-requests-limit: 10 42 | groups: 43 | kiota-dependencies: 44 | patterns: 45 | - "*kiota*" 46 | junit-dependencies: 47 | patterns: 48 | - "*junit*" 49 | open-telemetry: 50 | patterns: 51 | - "*opentelemetry*" 52 | - package-ecosystem: github-actions 53 | directory: "/" 54 | schedule: 55 | interval: daily 56 | open-pull-requests-limit: 10 57 | -------------------------------------------------------------------------------- /.github/workflows/release-please-gha.yml: -------------------------------------------------------------------------------- 1 | ## ----------------------------------------------------------------------------- 2 | # Copyright (c) Microsoft Corporation. All rights reserved. 3 | # Licensed under the MIT License. See LICENSE.txt in the project root for license information. 4 | ## ----------------------------------------------------------------------------- 5 | # 6 | # Summary: 7 | # This GitHub Actions workflow automates the release process using Release Please. 8 | # It triggers on pushes to the main branch, generates a GitHub App token using organization 9 | # variables and secrets, and then runs the release-please-action to manage versioning and changelogs. 10 | 11 | name: Release Please 12 | 13 | on: 14 | push: 15 | branches: 16 | - main 17 | 18 | jobs: 19 | release: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v5 23 | 24 | - name: Generate GitHub App token 25 | id: app-token 26 | uses: actions/create-github-app-token@v2 27 | with: 28 | app-id: ${{ vars.RELEASE_PLEASE_TOKEN_PROVIDER_APP_ID }} 29 | private-key: ${{ secrets.RELEASE_PLEASE_TOKEN_PROVIDER_PEM }} 30 | 31 | - name: Release Please 32 | uses: googleapis/release-please-action@v4 33 | with: 34 | token: ${{ steps.app-token.outputs.token }} 35 | config-file: release-please-config.json 36 | manifest-file: .release-please-manifest.json -------------------------------------------------------------------------------- /scripts/getLatestVersion.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT License. 3 | 4 | <# 5 | .Synopsis 6 | Retrieve the latest version of the library 7 | .Description 8 | Retrieves the latest version specified in the Gradle.Properties file 9 | Uses the retrieved values to update the environment variable VERSION_STRING 10 | .Parameter propertiesPath 11 | The path pointing to the gradle.properties file. 12 | #> 13 | 14 | Param( 15 | [string]$propertiesPath 16 | ) 17 | 18 | #Retrieve the current version from the Gradle.Properties file given the specified path 19 | if($propertiesPath -eq "" -or $null -eq $propertiesPath) { 20 | $propertiesPath = Join-Path -Path $PSScriptRoot -ChildPath "../gradle.properties" 21 | } 22 | $file = get-item $propertiesPath 23 | $findVersions = $file | Select-String -Pattern "mavenMajorVersion" -Context 0,2 24 | $content = Get-Content $propertiesPath 25 | 26 | $lineNumber = $findVersions.LineNumber - 1 27 | $versionIndex = $content[$lineNumber].IndexOf("=") 28 | $versionIndex += 2 # skipping =[space] 29 | $majorVersion = $content[$lineNumber].Substring($versionIndex) 30 | $lineNumber++ 31 | $minorVersion = $content[$lineNumber].Substring($versionIndex) 32 | $lineNumber++ 33 | $patchVersion = $content[$lineNumber].Substring($versionIndex) 34 | $version = "$majorVersion.$minorVersion.$patchVersion" 35 | 36 | #Set Task output to create tag 37 | Write-Output "::set-output name=tag::v${version}" -------------------------------------------------------------------------------- /.github/workflows/conflicting-pr-label.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: PullRequestConflicting 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the main branch 7 | on: 8 | workflow_dispatch: 9 | push: 10 | branches: [main, support/2.x.x] 11 | pull_request: 12 | types: [synchronize] 13 | branches: [main, support/2.x.x] 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | # This workflow contains a single job called "build" 18 | build: 19 | # The type of runner that the job will run on 20 | runs-on: ubuntu-latest 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | - name: check if prs are dirty 25 | uses: eps1lon/actions-label-merge-conflict@releases/2.x 26 | if: env.LABELING_TOKEN != '' && env.LABELING_TOKEN != null 27 | id: check 28 | with: 29 | dirtyLabel: "conflicting" 30 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 31 | continueOnMissingPermissions: true 32 | commentOnDirty: 'This pull request has conflicting changes, the author must resolve the conflicts before this pull request can be merged.' 33 | commentOnClean: 'Conflicts have been resolved. A maintainer will take a look shortly.' 34 | env: 35 | LABELING_TOKEN: ${{secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE users: 4 | # Settings specified in this file will override any Gradle settings 5 | # configured through the IDE. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # The size of the library demands a large amount of RAM to build. Increase as necessary if you get GC errors 21 | ## linux requires 10G, OSX requires 11G 22 | org.gradle.jvmargs=-Xmx2g 23 | org.gradle.parallel=true 24 | org.gradle.caching=true 25 | 26 | mavenGroupId = com.microsoft.graph 27 | mavenArtifactId = microsoft-graph-core 28 | mavenMajorVersion = 3 29 | mavenMinorVersion = 1 30 | mavenPatchVersion = 0 31 | mavenArtifactSuffix = 32 | 33 | 34 | #enable mavenCentralPublishingEnabled to publish to maven central 35 | mavenCentralSnapshotArtifactSuffix = -SNAPSHOT 36 | mavenCentralPublishingEnabled=false 37 | -------------------------------------------------------------------------------- /gradle/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | // Use JUnit test framework 3 | testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' 4 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 5 | testImplementation 'org.mockito:mockito-core:5.19.0' 6 | testImplementation 'io.opentelemetry:opentelemetry-api:1.54.0' 7 | testImplementation 'io.opentelemetry:opentelemetry-context:1.54.0' 8 | testImplementation 'io.github.std-uritemplate:std-uritemplate:1.0.6' 9 | implementation 'com.google.code.gson:gson:2.13.2' 10 | 11 | implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' 12 | 13 | implementation 'io.jsonwebtoken:jjwt-api:0.13.0' 14 | runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.13.0' 15 | runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.13.0' 16 | implementation 'com.auth0:jwks-rsa:0.23.0' 17 | 18 | api 'com.squareup.okhttp3:okhttp:4.12.0' 19 | api 'com.azure:azure-core:1.56.1' 20 | 21 | api 'com.microsoft.kiota:microsoft-kiota-abstractions:1.8.10' 22 | api 'com.microsoft.kiota:microsoft-kiota-authentication-azure:1.8.10' 23 | implementation 'com.microsoft.kiota:microsoft-kiota-http-okHttp:1.8.10' 24 | implementation 'com.microsoft.kiota:microsoft-kiota-serialization-json:1.8.10' 25 | implementation 'com.microsoft.kiota:microsoft-kiota-serialization-text:1.8.10' 26 | implementation 'com.microsoft.kiota:microsoft-kiota-serialization-form:1.8.10' 27 | implementation 'com.microsoft.kiota:microsoft-kiota-serialization-multipart:1.8.10' 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE users: 4 | # Settings specified in this file will override any Gradle settings 5 | # configured through the IDE. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # The size of the library demands a large amount of RAM to build. Increase as necessary if you get GC errors 21 | ## linux requires 10G, OSX requires 11G 22 | org.gradle.jvmargs=-Xmx2g 23 | 24 | mavenGroupId = com.microsoft.graph 25 | mavenArtifactId = microsoft-graph-core 26 | # x-release-please-start-major 27 | mavenMajorVersion = 3 28 | # x-release-please-end 29 | # x-release-please-start-minor 30 | mavenMinorVersion = 6 31 | # x-release-please-end 32 | # x-release-please-start-patch 33 | mavenPatchVersion = 5 34 | # x-release-please-end 35 | mavenArtifactSuffix = 36 | 37 | #enable mavenCentralPublishingEnabled to publish to maven central 38 | mavenCentralSnapshotArtifactSuffix = -SNAPSHOT 39 | mavenCentralPublishingEnabled=false 40 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/EncryptableSubscription.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import java.security.cert.CertificateEncodingException; 4 | import java.security.cert.X509Certificate; 5 | import java.util.Base64; 6 | import java.util.Objects; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import jakarta.annotation.Nullable; 10 | 11 | /** 12 | * EncryptableSubscription interface 13 | */ 14 | public interface EncryptableSubscription { 15 | 16 | /** 17 | * Sets the encryption certificate 18 | * @param certificate Base-64 encoded certificate to be used by Microsoft Graph to encrypt resource data 19 | */ 20 | public void setEncryptionCertificate(@Nullable final String certificate); 21 | 22 | /** 23 | * Returns the encryption certificate 24 | * @return encryption certificate 25 | */ 26 | public @Nullable String getEncryptionCertificate(); 27 | 28 | /** 29 | * Converts an X.509 Certificate object to Base-64 string and adds to the encryptableSubscription provided 30 | * @param subscription encryptable subscription 31 | * @param certificate X.509 Certificate 32 | * @throws CertificateEncodingException if the certificate cannot be encoded 33 | */ 34 | public static void addPublicEncryptionCertificate(@Nonnull final EncryptableSubscription subscription, @Nonnull final X509Certificate certificate) throws CertificateEncodingException { 35 | Objects.requireNonNull(subscription); 36 | Objects.requireNonNull(certificate); 37 | subscription.setEncryptionCertificate( 38 | Base64.getEncoder().encodeToString(certificate.getEncoded()) 39 | ); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | gradlePluginPortal() 5 | } 6 | 7 | dependencies { 8 | classpath "com.gradle:gradle-enterprise-gradle-plugin:3.19.2" 9 | classpath "com.android.tools.build:gradle:8.13.0" 10 | classpath "com.github.ben-manes:gradle-versions-plugin:0.52.0" 11 | } 12 | } 13 | 14 | repositories { 15 | google() 16 | gradlePluginPortal() 17 | mavenCentral() 18 | } 19 | 20 | apply plugin: "com.android.library" 21 | apply plugin: "com.github.ben-manes.versions" 22 | 23 | android { 24 | namespace "com.microsoft.graph" 25 | 26 | compileSdkVersion 36 27 | 28 | defaultConfig { 29 | versionCode 1 30 | versionName "1.0" 31 | minSdkVersion 26 32 | targetSdkVersion 36 33 | } 34 | 35 | buildTypes { 36 | release { 37 | minifyEnabled false 38 | } 39 | } 40 | 41 | compileOptions { 42 | sourceCompatibility JavaVersion.VERSION_1_8 43 | targetCompatibility JavaVersion.VERSION_1_8 44 | } 45 | 46 | lint { 47 | baseline = file("lint-baseline.xml") 48 | } 49 | 50 | lintOptions { 51 | textOutput "stdout" 52 | checkAllWarnings true 53 | warningsAsErrors true 54 | lintConfig file("lint.xml") 55 | } 56 | 57 | sourceSets { 58 | main { 59 | java.srcDirs = ['../src/main/java'] 60 | res.srcDirs = ['../src/main/java'] 61 | manifest.srcFile 'AndroidManifest.xml' 62 | } 63 | androidTest { 64 | setRoot '../src/test' 65 | } 66 | } 67 | } 68 | 69 | apply from: "../gradle/dependencies.gradle" 70 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/MockResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import java.io.IOException; 4 | 5 | import okhttp3.Interceptor; 6 | import okhttp3.MediaType; 7 | import okhttp3.Protocol; 8 | import okhttp3.Response; 9 | import okhttp3.ResponseBody; 10 | import okio.Buffer; 11 | 12 | class MockResponseHandler implements Interceptor { 13 | 14 | private int statusCode; 15 | 16 | public MockResponseHandler(int statusCode) { 17 | this.statusCode = statusCode; 18 | } 19 | 20 | public MockResponseHandler() { 21 | this.statusCode = 200; 22 | } 23 | 24 | @Override 25 | public Response intercept(Chain chain) throws IOException { 26 | final var request = chain.request(); 27 | final var requestBody = request.body(); 28 | if (request != null && requestBody != null) { 29 | final var buffer = new Buffer(); 30 | requestBody.writeTo(buffer); 31 | return new Response.Builder() 32 | .code(this.statusCode) 33 | .message("OK") 34 | .protocol(Protocol.HTTP_1_1) 35 | .request(request) 36 | .body( 37 | ResponseBody.create( 38 | buffer.readByteArray(), MediaType.parse("application/json"))) 39 | .build(); 40 | } 41 | return new Response.Builder() 42 | .code(this.statusCode) 43 | .message("OK") 44 | .protocol(Protocol.HTTP_1_1) 45 | .request(request) 46 | .body(ResponseBody.create("", MediaType.parse("application/json"))) 47 | .build(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestEventsResponse.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | 4 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 5 | import com.microsoft.kiota.serialization.Parsable; 6 | import com.microsoft.kiota.serialization.ParseNode; 7 | import com.microsoft.kiota.serialization.SerializationWriter; 8 | 9 | import jakarta.annotation.Nonnull; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Objects; 14 | import java.util.function.Consumer; 15 | 16 | public class TestEventsResponse extends BaseCollectionPaginationCountResponse { 17 | public List value; 18 | 19 | public TestEventsResponse() { 20 | super(); 21 | } 22 | 23 | public List getValue() { 24 | return value; 25 | } 26 | 27 | public void setValue(List value) { 28 | this.value = value; 29 | } 30 | @Nonnull 31 | public Map> getFieldDeserializers() { 32 | final HashMap> deserializerMap = new HashMap>(super.getFieldDeserializers()); 33 | deserializerMap.put("value", (n) -> { this.setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)); }); 34 | return deserializerMap; 35 | } 36 | 37 | public void serialize(@Nonnull SerializationWriter writer) { 38 | Objects.requireNonNull(writer); 39 | super.serialize(writer); 40 | writer.writeCollectionOfObjectValues("value", getValue()); 41 | } 42 | 43 | public static TestEventsResponse createFromDiscriminatorValue(ParseNode parseNode) { 44 | Objects.requireNonNull(parseNode); 45 | return new TestEventsResponse(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: Static analysis with SonarCloud 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: [main, support/2.x.x] 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | 9 | env: 10 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 11 | 12 | jobs: 13 | checksecret: 14 | name: check if SONAR_TOKEN is set in github secrets 15 | runs-on: ubuntu-latest 16 | outputs: 17 | is_SONAR_TOKEN_set: ${{ steps.checksecret_job.outputs.is_SONAR_TOKEN_set }} 18 | steps: 19 | - name: Check whether unity activation requests should be done 20 | id: checksecret_job 21 | run: | 22 | echo "is_SONAR_TOKEN_set=${{ env.SONAR_TOKEN != '' }}" >> $GITHUB_OUTPUT 23 | build: 24 | needs: [checksecret] 25 | if: needs.checksecret.outputs.is_SONAR_TOKEN_set == 'true' 26 | name: Build 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v5 30 | with: 31 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 32 | - name: Set up JDK 33 | uses: actions/setup-java@v5 34 | with: 35 | java-version: 21 36 | distribution: 'temurin' 37 | cache: gradle 38 | - name: Cache SonarCloud packages 39 | uses: actions/cache@v4 40 | with: 41 | path: ~/.sonar/cache 42 | key: ${{ runner.os }}-sonar 43 | restore-keys: ${{ runner.os }}-sonar 44 | - name: Cache Gradle packages 45 | uses: actions/cache@v4 46 | with: 47 | path: ~/.gradle/caches 48 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 49 | restore-keys: ${{ runner.os }}-gradle 50 | - name: Build and analyze 51 | env: 52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 53 | run: ./gradlew build sonarqube --info 54 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/DiscoverUrlAdapter.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URI; 5 | import java.net.URISyntaxException; 6 | import java.security.Key; 7 | import java.util.Objects; 8 | 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.auth0.jwk.Jwk; 12 | import com.auth0.jwk.JwkProvider; 13 | import com.auth0.jwk.UrlJwkProvider; 14 | 15 | import io.jsonwebtoken.JweHeader; 16 | import io.jsonwebtoken.JwsHeader; 17 | import io.jsonwebtoken.LocatorAdapter; 18 | import jakarta.annotation.Nonnull; 19 | import jakarta.annotation.Nullable; 20 | 21 | /** 22 | * DiscoverUrlAdapter class 23 | */ 24 | public class DiscoverUrlAdapter extends LocatorAdapter { 25 | 26 | /** 27 | * Key store 28 | */ 29 | private final JwkProvider keyStore; 30 | 31 | /** 32 | * Constructor 33 | * @param keyDiscoveryUrl the JWKS endpoint to use to retrieve signing keys 34 | * @throws URISyntaxException if uri is invalid 35 | * @throws MalformedURLException if url is invalid 36 | */ 37 | public DiscoverUrlAdapter(@Nonnull final String keyDiscoveryUrl) 38 | throws URISyntaxException, MalformedURLException { 39 | this.keyStore = 40 | new UrlJwkProvider(new URI(Objects.requireNonNull(keyDiscoveryUrl)).toURL()); 41 | } 42 | 43 | @Override 44 | protected @Nullable Key locate(@Nonnull JwsHeader header) { 45 | Objects.requireNonNull(header); 46 | try { 47 | String keyId = header.getKeyId(); 48 | Jwk publicKey = keyStore.get(keyId); 49 | return publicKey.getPublicKey(); 50 | } catch (final Exception e) { 51 | throw new IllegalArgumentException("Could not locate key", e); 52 | } 53 | } 54 | 55 | @Override 56 | protected @Nullable Key locate(@Nonnull JweHeader header) { 57 | return null; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/FeatureFlag.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | /** 4 | * The class which holds the values of each feature flag. 5 | * Values are set such that they translate seamlessly to base 2. 6 | */ 7 | public final class FeatureFlag { 8 | private FeatureFlag(){} 9 | /** The value of the None flag, 0.*/ 10 | public static final int NONE_FLAG = 0; 11 | /** The value of the Redirect Handler flag, 1. */ 12 | public static final int REDIRECT_HANDLER_FLAG = 1; 13 | /** The value of the Retry Handler flag, 10. */ 14 | public static final int RETRY_HANDLER_FLAG = 2; 15 | /** The value of the Auth Handler flag, 100. */ 16 | public static final int AUTH_HANDLER_FLAG = 4; 17 | /** The value of the Default Http flag, 1000. */ 18 | public static final int DEFAULT_HTTP_FLAG = 8; 19 | /** The value of the Logging Handler flag, 10000. */ 20 | public static final int LOGGING_HANDLER_FLAG = 16; 21 | /** The value of the Service Discovery flag, 100000. */ 22 | public static final int SERVICE_DISCOVERY_FLAG = 32; 23 | /** The value of the Compression Handler flag, 1000000. */ 24 | public static final int COMPRESSION_HANDLER_FLAG = 64; 25 | /** The value of the Connection Pool flag, 10000000. */ 26 | public static final int CONNECTION_POOL_FLAG = 128; 27 | /** The value of the Long Running Operation flag, 100000000. */ 28 | public static final int LONG_RUNNING_OP_FLAG = 256; 29 | /** The value of the Batch Request flag, 1000000000. */ 30 | public static final int BATCH_REQUEST_FLAG = 512; 31 | /** The value of the Page Iterator flag, 10000000000. */ 32 | public static final int PAGE_ITERATOR_FLAG = 1024; 33 | /** The value of the File Upload flag, 100000000000. */ 34 | public static final int FILE_UPLOAD_FLAG = 2048; 35 | /** The value of the UrlReplacement flag, 1000000000000. */ 36 | public static final int URL_REPLACEMENT_FLAG = 4096; 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestChatMessage.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | import jakarta.annotation.Nonnull; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.Objects; 12 | import java.util.function.Consumer; 13 | 14 | public class TestChatMessage implements Parsable, AdditionalDataHolder { 15 | 16 | private HashMap additionalData; 17 | private String etag; 18 | 19 | public TestChatMessage() { 20 | } 21 | 22 | public String getETag() { 23 | return etag; 24 | } 25 | 26 | public void setEtag(String etag) { 27 | this.etag = etag; 28 | } 29 | 30 | @Nonnull 31 | public HashMap getAdditionalData() { 32 | return additionalData; 33 | } 34 | 35 | public void setAdditionalData(HashMap additionalData) { 36 | this.additionalData = additionalData; 37 | } 38 | 39 | public HashMap> getFieldDeserializers() { 40 | HashMap> fieldDeserializers = new HashMap<>(); 41 | fieldDeserializers.put("etag", (n) -> { setEtag(n.getStringValue()); }); 42 | return fieldDeserializers; 43 | } 44 | 45 | public void serialize(SerializationWriter writer) { 46 | Objects.requireNonNull(writer); 47 | writer.writeStringValue("etag", getETag()); 48 | writer.writeAdditionalData(getAdditionalData()); 49 | } 50 | 51 | public static TestChatMessage createFromDiscriminatorValue(ParseNode parseNode) { 52 | if (parseNode == null) { 53 | throw new IllegalArgumentException("The parseNode cannot be null."); 54 | } 55 | return new TestChatMessage(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestEventsDeltaResponse.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import java.util.*; 9 | import java.util.function.Consumer; 10 | 11 | public class TestEventsDeltaResponse extends BaseCollectionPaginationCountResponse { 12 | private String odataDeltaLink; 13 | public List value; 14 | 15 | public TestEventsDeltaResponse() { 16 | super(); 17 | } 18 | 19 | public String getOdataDeltaLink() { 20 | return odataDeltaLink; 21 | } 22 | 23 | public void setOdataDeltaLink(String odataDeltaLink) { 24 | this.odataDeltaLink = odataDeltaLink; 25 | } 26 | 27 | public List getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(List value) { 32 | this.value = value; 33 | } 34 | 35 | public Map> getFieldDeserializers() { 36 | final HashMap> deserializerMap = new HashMap>(super.getFieldDeserializers()); 37 | deserializerMap.put("value", (n) -> { this.setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)); }); 38 | return deserializerMap; 39 | } 40 | 41 | public void serialize(SerializationWriter writer) { 42 | Objects.requireNonNull(writer); 43 | super.serialize(writer); 44 | writer.writeCollectionOfObjectValues("value", getValue()); 45 | } 46 | 47 | public static TestEventsDeltaResponse createFromDiscriminatorValue(ParseNode parseNode) { 48 | if (parseNode == null) { 49 | throw new IllegalArgumentException("parseNode"); 50 | } 51 | return new TestEventsDeltaResponse(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/IUploadSession.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | 6 | import jakarta.annotation.Nonnull; 7 | import jakarta.annotation.Nullable; 8 | import java.time.OffsetDateTime; 9 | import java.util.List; 10 | 11 | /** 12 | * Interface defining and UploadSession 13 | */ 14 | public interface IUploadSession extends Parsable, AdditionalDataHolder { 15 | /** 16 | * Gets the Upload Url. 17 | * The URL endpoint that accepts PUT requests for byte ranges of the file. 18 | * @return the upload Url 19 | */ 20 | @Nonnull 21 | String getUploadUrl(); 22 | /** 23 | * Sets the Upload Url 24 | * @param url the upload Url for the session 25 | */ 26 | void setUploadUrl(@Nonnull final String url); 27 | /** 28 | * Gets the Next Expected Ranges. 29 | * A collection of byte ranges that the server is missing for the file. These ranges are zero indexed and of the format 'start-end' (e.g. '0-26' to indicate the first 27 bytes of the file). When uploading files as Outlook attachments, instead of a collection of ranges, this property always indicates a single value '{start}', the location in the file where the next upload should begin. 30 | * @return the Next Expected Ranges. 31 | */ 32 | @Nullable 33 | List getNextExpectedRanges(); 34 | /** 35 | * Sets the ranges that are yet to be uploaded. 36 | * @param nextExpectedRanges the byte ranges yet to be uploaded. 37 | */ 38 | void setNextExpectedRanges(@Nonnull final List nextExpectedRanges); 39 | /** 40 | * Expiration date of the upload session 41 | * @return the expiration date. 42 | */ 43 | @Nullable 44 | OffsetDateTime getExpirationDateTime(); 45 | /** 46 | * Set the expiration date of the UploadSession 47 | * @param dateTime the expiration date of the UploadSession. 48 | */ 49 | void setExpirationDateTime(@Nonnull final OffsetDateTime dateTime); 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestDrive.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.function.Consumer; 12 | 13 | public class TestDrive implements Parsable, AdditionalDataHolder { 14 | public String id; 15 | public String odataType; 16 | public String name; 17 | public HashMap additionalData; 18 | 19 | public TestDrive() { 20 | this.odataType = "microsoft.graph.drive"; 21 | this.additionalData = new HashMap<>(); 22 | } 23 | 24 | @Override 25 | public HashMap> getFieldDeserializers() { 26 | HashMap> props = new HashMap<>(); 27 | props.put("@odata.type", (n) -> this.odataType = n.getStringValue()); 28 | props.put("id", (n) -> this.id = n.getStringValue()); 29 | props.put("name", (n) -> this.name = n.getStringValue()); 30 | return props; 31 | } 32 | 33 | @Override 34 | public void serialize(SerializationWriter writer) { 35 | if (writer == null) { 36 | throw new IllegalArgumentException("The writer parameter cannot be null."); 37 | } 38 | writer.writeStringValue("@odata.type", odataType); 39 | writer.writeStringValue("id", id); 40 | writer.writeStringValue("name", name); 41 | writer.writeAdditionalData(additionalData); 42 | } 43 | 44 | @Nonnull 45 | @Override 46 | public Map getAdditionalData() { 47 | return this.additionalData; 48 | } 49 | 50 | public static TestDrive createFromDiscriminatorValue(ParseNode parseNode) { 51 | if (parseNode == null) { 52 | throw new IllegalArgumentException("parseNode cannot be null"); 53 | } 54 | return new TestDrive(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestDriveItem.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Objects; 12 | import java.util.function.Consumer; 13 | 14 | public class TestDriveItem implements Parsable, AdditionalDataHolder { 15 | 16 | public String id; 17 | public String oDataType = "#microsoft.graph.driveItem"; 18 | public String name; 19 | public long size; 20 | public HashMap additionalData = new HashMap<>(); 21 | 22 | public TestDriveItem() {} 23 | 24 | @Nonnull 25 | @Override 26 | public Map getAdditionalData() { 27 | return this.additionalData; 28 | } 29 | 30 | @Nonnull 31 | @Override 32 | public Map> getFieldDeserializers() { 33 | final HashMap> deserializerMap = new HashMap>(); 34 | deserializerMap.put("id", (n)-> this.id = n.getStringValue()); 35 | deserializerMap.put("@odata.type", (n)-> this.oDataType = n.getStringValue()); 36 | deserializerMap.put("name", (n)-> this.name = n.getStringValue()); 37 | deserializerMap.put("size", (n)-> this.size = n.getLongValue()); 38 | return deserializerMap; 39 | } 40 | 41 | @Override 42 | public void serialize(@Nonnull SerializationWriter writer) { 43 | Objects.requireNonNull(writer); 44 | writer.writeStringValue("id", id); 45 | writer.writeStringValue("@odata.type", oDataType); 46 | writer.writeStringValue("name", name); 47 | writer.writeLongValue("size", size); 48 | } 49 | 50 | public static TestDriveItem createFromDiscriminatorValue(ParseNode parseNode) { 51 | Objects.requireNonNull(parseNode); 52 | return new TestDriveItem(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestNoteBook.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.function.Consumer; 12 | 13 | public class TestNoteBook implements Parsable, AdditionalDataHolder { 14 | public String id; 15 | public String odataType; 16 | public String displayName; 17 | public HashMap additionalData; 18 | 19 | public TestNoteBook() { 20 | this.odataType = "microsoft.graph.notebook"; 21 | this.additionalData = new HashMap<>(); 22 | } 23 | 24 | @Override 25 | public HashMap> getFieldDeserializers() { 26 | HashMap> props = new HashMap<>(); 27 | props.put("@odata.type", (n) -> odataType = n.getStringValue()); 28 | props.put("id", (n) -> id = n.getStringValue()); 29 | props.put("displayName", (n) -> displayName = n.getStringValue()); 30 | return props; 31 | } 32 | 33 | @Override 34 | public void serialize(SerializationWriter writer) { 35 | if (writer == null) { 36 | throw new IllegalArgumentException("The writer parameter cannot be null."); 37 | } 38 | writer.writeStringValue("@odata.type", odataType); 39 | writer.writeStringValue("id", id); 40 | writer.writeStringValue("displayName", displayName); 41 | writer.writeAdditionalData(additionalData); 42 | } 43 | 44 | public static TestNoteBook createFromDiscriminatorValue(ParseNode parseNode) { 45 | if (parseNode == null) { 46 | throw new IllegalArgumentException("The parseNode parameter cannot be null."); 47 | } 48 | return new TestNoteBook(); 49 | } 50 | @Nonnull 51 | @Override 52 | public Map getAdditionalData() { 53 | return this.additionalData; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /scripts/validatePackageContents.ps1: -------------------------------------------------------------------------------- 1 | # Checks that expected files are present & have contents after the publish process to the local cache 2 | param( 3 | [Parameter(Mandatory=$true)][string] $ArtifactId, 4 | [Parameter(Mandatory=$true)][string] $Version, 5 | [Parameter()][string] $GroupId = "com.microsoft.graph", 6 | [Parameter()][string] $MavenLocalCachePath = "~" + [System.IO.Path]::DirectorySeparatorChar + ".m2" + [System.IO.Path]::DirectorySeparatorChar + "repository", 7 | [Parameter()][bool] $ValidateMavenMetadata = $true 8 | ) 9 | 10 | $groupIdPath = $GroupId -replace "\.", [System.IO.Path]::DirectorySeparatorChar 11 | $packagePath = Join-Path -Path $groupIdPath -ChildPath $ArtifactId 12 | $packageFullPath = Join-Path -Path $MavenLocalCachePath -ChildPath $packagePath -AdditionalChildPath $Version 13 | 14 | Write-Output "---------------------------------------------------" 15 | Write-Output "Validating package contents at $packageFullPath" 16 | 17 | if(-not (Test-Path -Path $packageFullPath)) { 18 | Write-Output "Package not found in local cache." 19 | exit 1 20 | } 21 | 22 | Write-Output "Package exists in local cache." 23 | 24 | $expectedFiles = @( 25 | "-javadoc.jar", 26 | "-javadoc.jar.asc", 27 | "-sources.jar", 28 | "-sources.jar.asc", 29 | ".module", 30 | ".module.asc", 31 | ".pom", 32 | ".pom.asc", 33 | ".jar", 34 | ".jar.asc" 35 | ) 36 | 37 | foreach($file in $expectedFiles) { 38 | $file = $ArtifactId + "-" + $Version + $file 39 | $filePath = Join-Path -Path $packageFullPath -ChildPath $file 40 | if(-not (Test-Path -Path $filePath)) { 41 | Write-Output "Expected file $file not found in package." 42 | exit 1 43 | } 44 | $fileSize = (Get-Item -Path $filePath).length 45 | if($fileSize -eq 0) { 46 | Write-Output "File $file is empty." 47 | exit 1 48 | } 49 | } 50 | 51 | $mavenMetadataFiles = Get-ChildItem -Path $packageFullPath -Filter "maven-metadata*.xml" 52 | if($mavenMetadataFiles.Count -eq 0 -and $ValidateMavenMetadata -eq $true) { 53 | Write-Output "No maven-metadata*.xml files found in package." 54 | exit 1 55 | } 56 | 57 | Write-Output "Package $ArtifactId is valid." 58 | Write-Output "---------------------------------------------------" 59 | exit 0 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestEmailAddress.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.function.Consumer; 12 | 13 | public class TestEmailAddress implements Parsable, AdditionalDataHolder { 14 | public String name; 15 | public String address; 16 | public HashMap additionalData; 17 | public String odataType; 18 | 19 | public TestEmailAddress() { 20 | this.odataType = "microsoft.graph.emailAddress"; 21 | this.additionalData = new HashMap<>(); 22 | } 23 | 24 | @Override 25 | public HashMap> getFieldDeserializers() { 26 | HashMap> props = new HashMap<>(); 27 | props.put("@odata.type", (n) -> this.odataType = n.getStringValue()); 28 | props.put("name", (n) -> this.name = n.getStringValue()); 29 | props.put("address", (n) -> this.address = n.getStringValue()); 30 | return props; 31 | } 32 | 33 | @Override 34 | public void serialize(SerializationWriter writer) { 35 | if (writer == null) { 36 | throw new IllegalArgumentException("The writer parameter cannot be null."); 37 | } 38 | writer.writeStringValue("name", name); 39 | writer.writeStringValue("address", address); 40 | writer.writeStringValue("@odata.type", odataType); 41 | writer.writeAdditionalData(additionalData); 42 | } 43 | 44 | public static TestEmailAddress createFromDiscriminatorValue(ParseNode parseNode) { 45 | if (parseNode == null) { 46 | throw new IllegalArgumentException("The parseNode parameter cannot be null."); 47 | } 48 | return new TestEmailAddress(); 49 | } 50 | 51 | @Nonnull 52 | @Override 53 | public Map getAdditionalData() { 54 | return this.additionalData; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestRecipient.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.function.Consumer; 12 | 13 | public class TestRecipient implements Parsable, AdditionalDataHolder { 14 | public TestEmailAddress emailAddress; 15 | public HashMap additionalData; 16 | public String ODataType; 17 | 18 | public TestRecipient() { 19 | this.ODataType = "microsoft.graph.recipient"; 20 | } 21 | 22 | @Override 23 | public HashMap> getFieldDeserializers() { 24 | HashMap> props = new HashMap<>(); 25 | props.put("@odata.type", (n) -> this.ODataType = n.getStringValue()); 26 | props.put("emailAddress", (n) -> this.emailAddress = n.getObjectValue(TestEmailAddress::createFromDiscriminatorValue)); 27 | return props; 28 | } 29 | 30 | @Override 31 | public void serialize(@Nonnull SerializationWriter writer) { 32 | writer.writeStringValue("@odata.type", ODataType); 33 | writer.writeObjectValue("emailAddress", emailAddress); 34 | writer.writeAdditionalData(additionalData); 35 | } 36 | 37 | public static TestRecipient createFromParseNode(ParseNode parseNode) { 38 | if (parseNode == null) { 39 | throw new IllegalArgumentException("The parseNode parameter cannot be null."); 40 | } 41 | ParseNode mappingValueNode = parseNode.getChildNode("@odata.type"); 42 | assert mappingValueNode != null; 43 | String mappingValue = mappingValueNode.getStringValue(); 44 | if (mappingValue == null) { 45 | return new TestRecipient(); 46 | } 47 | if (mappingValue.equals("microsoft.graph.attendee")) { 48 | return new TestAttendee(); 49 | } 50 | return new TestRecipient(); 51 | } 52 | 53 | @Nonnull 54 | @Override 55 | public Map getAdditionalData() { 56 | return this.additionalData; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 4.0.0 8 | 9 | com.microsoft.graph 10 | microsoft-graph-core 11 | 12 | 3.6.5 13 | 14 | pom 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.google.code.gson 24 | gson 25 | 2.13.2 26 | 27 | 28 | com.squareup.okhttp3 29 | okhttp 30 | 4.12.0 31 | 32 | 33 | com.azure 34 | azure-core 35 | 1.56.1 36 | 37 | 38 | org.junit.jupiter 39 | junit-jupiter-api 40 | 5.13.4 41 | test 42 | 43 | 44 | org.junit.jupiter 45 | junit-jupiter-params 46 | 5.13.4 47 | test 48 | 49 | 50 | org.mockito 51 | mockito-inline 52 | 5.2.0 53 | test 54 | 55 | 56 | com.github.spotbugs 57 | spotbugs-annotations 58 | 4.9.4 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestDateTimeTimeZone.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import java.util.HashMap; 9 | import java.util.function.Consumer; 10 | 11 | public class TestDateTimeTimeZone implements Parsable, AdditionalDataHolder { 12 | private String dateTime; 13 | private String timeZone; 14 | private HashMap additionalData = new HashMap<>(); 15 | private String oDataType; 16 | 17 | public TestDateTimeTimeZone() { 18 | this.oDataType = "microsoft.graph.dateTimeTimeZone"; 19 | } 20 | 21 | public String getDateTime() { 22 | return dateTime; 23 | } 24 | 25 | public void setDateTime(String dateTime) { 26 | this.dateTime = dateTime; 27 | } 28 | 29 | public String getTimeZone() { 30 | return timeZone; 31 | } 32 | 33 | public void setTimeZone(String timeZone) { 34 | this.timeZone = timeZone; 35 | } 36 | 37 | public HashMap getAdditionalData() { 38 | return additionalData; 39 | } 40 | 41 | public void setAdditionalData(HashMap additionalData) { 42 | this.additionalData = additionalData; 43 | } 44 | 45 | public String getODataType() { 46 | return oDataType; 47 | } 48 | 49 | public void setODataType(String oDataType) { 50 | this.oDataType = oDataType; 51 | } 52 | 53 | public HashMap> getFieldDeserializers() { 54 | HashMap> fieldDeserializers = new HashMap<>(); 55 | fieldDeserializers.put("dateTime", (n) -> setDateTime(n.getStringValue())); 56 | fieldDeserializers.put("timeZone", (n) -> setTimeZone(n.getStringValue())); 57 | fieldDeserializers.put("@odata.type", (n) -> setODataType(n.getStringValue())); 58 | return fieldDeserializers; 59 | } 60 | 61 | public void serialize(SerializationWriter writer) { 62 | writer.writeStringValue("dateTime", dateTime); 63 | writer.writeStringValue("timeZone", timeZone); 64 | writer.writeStringValue("@odata.type", oDataType); 65 | writer.writeAdditionalData(additionalData); 66 | } 67 | 68 | public static TestDateTimeTimeZone createFromDiscriminatorValue(ParseNode parseNode) { 69 | return new TestDateTimeTimeZone(); 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/tasks/PageIteratorBuilder.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.tasks; 2 | 3 | import com.microsoft.graph.core.requests.IBaseClient; 4 | import com.microsoft.kiota.RequestAdapter; 5 | import com.microsoft.kiota.RequestInformation; 6 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 7 | import com.microsoft.kiota.serialization.Parsable; 8 | import com.microsoft.kiota.serialization.ParsableFactory; 9 | 10 | import jakarta.annotation.Nonnull; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.function.UnaryOperator; 13 | 14 | interface PageIteratorBuilder { 15 | /** 16 | * Sets the client for the PageIteratorBuilder. 17 | * @param client the client to set. 18 | */ 19 | public PageIteratorBuilder client(@Nonnull IBaseClient client); 20 | /** 21 | * Sets the request adapter for the PageIteratorBuilder. 22 | * @param requestAdapter the request adapter to set. 23 | */ 24 | public PageIteratorBuilder requestAdapter(@Nonnull RequestAdapter requestAdapter); 25 | /** 26 | * Sets the page to be iterated over. 27 | * @param collectionPage the page to be iterated over. 28 | */ 29 | public PageIteratorBuilder collectionPage(@Nonnull TCollectionPage collectionPage) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException; 30 | /** 31 | * Sets factory to use for creating a collection page. 32 | * @param collectionPageFactory the factory to use for creating a collection page. 33 | */ 34 | public PageIteratorBuilder collectionPageFactory(@Nonnull ParsableFactory collectionPageFactory); 35 | /** 36 | * Sets the function to configure each subsequent request. 37 | * @param requestConfigurator function to configure each subsequent request. 38 | */ 39 | public PageIteratorBuilder requestConfigurator(@Nonnull UnaryOperator requestConfigurator); 40 | /** 41 | * Build the PageIterator. 42 | * Should fail if request adapter is not set. 43 | * Should fail if current collection page is not set. 44 | * Should fail if collection page factory is not set. 45 | * Should fail if process page item callback is not set. 46 | * @return the built PageIterator. 47 | */ 48 | PageIterator build() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestItemBody.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import java.util.HashMap; 9 | import java.util.function.Consumer; 10 | 11 | public class TestItemBody implements Parsable, AdditionalDataHolder { 12 | 13 | private TestBodyType contentType; 14 | private String content; 15 | private HashMap additionalData = new HashMap<>(); 16 | private String oDataType; 17 | 18 | public TestItemBody() { 19 | this.oDataType = "microsoft.graph.itemBody"; 20 | } 21 | 22 | public TestBodyType getContentType() { 23 | return contentType; 24 | } 25 | 26 | public void setContentType(TestBodyType contentType) { 27 | this.contentType = contentType; 28 | } 29 | 30 | public String getContent() { 31 | return content; 32 | } 33 | 34 | public void setContent(String content) { 35 | this.content = content; 36 | } 37 | 38 | public HashMap getAdditionalData() { 39 | return additionalData; 40 | } 41 | 42 | public void setAdditionalData(HashMap additionalData) { 43 | this.additionalData = additionalData; 44 | } 45 | 46 | public String getODataType() { 47 | return oDataType; 48 | } 49 | 50 | public void setODataType(String oDataType) { 51 | this.oDataType = oDataType; 52 | } 53 | 54 | public HashMap> getFieldDeserializers() { 55 | return new HashMap>() {{ 56 | put("@odata.type", (n) -> { setODataType(n.getStringValue()); }); 57 | put("contentType", (n) -> { setContentType(n.getEnumValue(TestBodyType::forValue)); }); 58 | put("content", (n) -> { setContent(n.getStringValue()); }); 59 | }}; 60 | } 61 | 62 | public void serialize(SerializationWriter writer) { 63 | if (writer == null) { 64 | throw new IllegalArgumentException("writer cannot be null"); 65 | } 66 | writer.writeStringValue("@odata.type", oDataType); 67 | writer.writeEnumValue("contentType", contentType); 68 | writer.writeStringValue("content", content); 69 | writer.writeAdditionalData(additionalData); 70 | } 71 | 72 | public static TestItemBody createFromDiscriminatorValue(ParseNode parseNode) { 73 | if (parseNode == null) { 74 | throw new IllegalArgumentException("parseNode cannot be null"); 75 | } 76 | return new TestItemBody(); 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/BaseClient.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core; 2 | 3 | import com.microsoft.graph.core.requests.BaseGraphRequestAdapter; 4 | import com.microsoft.graph.core.requests.BatchRequestBuilder; 5 | import com.microsoft.graph.core.requests.IBaseClient; 6 | import com.microsoft.kiota.RequestAdapter; 7 | import com.microsoft.kiota.authentication.AuthenticationProvider; 8 | 9 | import jakarta.annotation.Nonnull; 10 | 11 | /** 12 | * Default client implementation. 13 | */ 14 | public class BaseClient implements IBaseClient { 15 | 16 | private RequestAdapter requestAdapter; 17 | private BatchRequestBuilder batchRequestBuilder; 18 | 19 | /** 20 | * Constructor requiring only a RequestAdapter. 21 | * 22 | * @param requestAdapter the specified RequestAdapter used to complete requests. 23 | */ 24 | public BaseClient(@Nonnull RequestAdapter requestAdapter) { 25 | setRequestAdapter(requestAdapter); 26 | } 27 | /** 28 | * Constructor requiring only an AuthenticationProvider. 29 | * 30 | * @param authenticationProvider the specified AuthenticationProvider for use in requests. 31 | */ 32 | @SuppressWarnings("LambdaLast") 33 | public BaseClient(@Nonnull AuthenticationProvider authenticationProvider) { 34 | this(new BaseGraphRequestAdapter(authenticationProvider)); 35 | } 36 | /** 37 | * Constructor requiring an AuthenticationProvider and Base URL. 38 | * 39 | * @param authenticationProvider the specified AuthenticationProvider for use in requests. 40 | * @param baseUrl the specified base URL for use in requests. 41 | */ 42 | @SuppressWarnings("LambdaLast") 43 | public BaseClient(@Nonnull AuthenticationProvider authenticationProvider, @Nonnull String baseUrl) { 44 | this(new BaseGraphRequestAdapter(authenticationProvider, baseUrl)); 45 | } 46 | 47 | /** 48 | * Method to set the RequestAdapter property 49 | * @param requestAdapter specifies the desired RequestAdapter 50 | */ 51 | @Override 52 | public void setRequestAdapter(@Nonnull final RequestAdapter requestAdapter) { 53 | this.requestAdapter = requestAdapter; 54 | } 55 | 56 | /** 57 | * Returns the current RequestAdapter for sending requests 58 | * @return the RequestAdapter currently in use 59 | */ 60 | @Nonnull 61 | @Override 62 | public RequestAdapter getRequestAdapter() { 63 | return this.requestAdapter; 64 | } 65 | 66 | /** 67 | * Gets the BatchRequestBuilder 68 | * @return the BatchRequestBuilder instance 69 | */ 70 | @Override 71 | @Nonnull 72 | public BatchRequestBuilder getBatchRequestBuilder() { 73 | if(this.batchRequestBuilder == null) { 74 | this.batchRequestBuilder = new BatchRequestBuilder(getRequestAdapter()); 75 | } 76 | return this.batchRequestBuilder; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.authentication; 2 | 3 | import jakarta.annotation.Nonnull; 4 | import jakarta.annotation.Nullable; 5 | 6 | import com.azure.core.credential.TokenCredential; 7 | import com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider; 8 | import com.microsoft.kiota.authentication.ObservabilityOptions; 9 | /** Implementation of Authentication provider for Azure Identity with Microsoft Graph defaults */ 10 | public class AzureIdentityAuthenticationProvider extends BaseBearerTokenAuthenticationProvider { 11 | /** 12 | * Creates a new instance of AzureIdentityAuthenticationProvider. 13 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 14 | * @param allowedHosts The list of allowed hosts for which to request access tokens. 15 | * @param scopes The scopes to request access tokens for. 16 | */ 17 | @SuppressWarnings("LambdaLast") 18 | public AzureIdentityAuthenticationProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, @Nonnull final String... scopes) { 19 | this(tokenCredential, allowedHosts, null, scopes); 20 | } 21 | /** 22 | * Creates a new instance of AzureIdentityAuthenticationProvider. 23 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 24 | * @param allowedHosts The list of allowed hosts for which to request access tokens. 25 | * @param observabilityOptions The observability options to use. 26 | * @param scopes The scopes to request access tokens for. 27 | */ 28 | @SuppressWarnings("LambdaLast") 29 | public AzureIdentityAuthenticationProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, @Nullable final ObservabilityOptions observabilityOptions, @Nonnull final String... scopes) { 30 | this(tokenCredential, allowedHosts, observabilityOptions, true, scopes); 31 | } 32 | 33 | /** 34 | * Creates a new instance of AzureIdentityAuthenticationProvider. 35 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 36 | * @param allowedHosts The list of allowed hosts for which to request access tokens. 37 | * @param observabilityOptions The observability options to use. 38 | * @param isCaeEnabled Whether to enable Continuous Access Evaluation, defaults to true. 39 | * @param scopes The scopes to request access tokens for. 40 | */ 41 | @SuppressWarnings("LambdaLast") 42 | public AzureIdentityAuthenticationProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, @Nullable final ObservabilityOptions observabilityOptions, final boolean isCaeEnabled, @Nonnull final String... scopes) { 43 | super(new AzureIdentityAccessTokenProvider(tokenCredential, allowedHosts, observabilityOptions, isCaeEnabled, scopes)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAccessTokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.authentication; 2 | 3 | import java.util.HashSet; 4 | 5 | import jakarta.annotation.Nonnull; 6 | import jakarta.annotation.Nullable; 7 | 8 | import com.azure.core.credential.TokenCredential; 9 | import com.microsoft.kiota.authentication.ObservabilityOptions; 10 | 11 | /** AzureIdentityAccessTokenProvider wrapper from Kiota library with Microsoft Graph defaults. */ 12 | public class AzureIdentityAccessTokenProvider extends com.microsoft.kiota.authentication.AzureIdentityAccessTokenProvider { 13 | /** 14 | * Creates a new instance of AzureIdentityAccessTokenProvider. 15 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 16 | */ 17 | public AzureIdentityAccessTokenProvider(@Nonnull TokenCredential tokenCredential) { 18 | this(tokenCredential, new String[] {}, null); 19 | } 20 | /** 21 | * Creates a new instance of AzureIdentityAccessTokenProvider. 22 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 23 | * @param allowedHosts The list of allowed hosts for which to request access tokens. 24 | * @param scopes The scopes to request access tokens for. 25 | * @param observabilityOptions The observability options to use. 26 | */ 27 | @SuppressWarnings("LambdaLast") 28 | public AzureIdentityAccessTokenProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, 29 | @Nullable final ObservabilityOptions observabilityOptions, @Nonnull final String... scopes) { 30 | this(tokenCredential, allowedHosts, observabilityOptions, true, scopes); 31 | } 32 | 33 | /** 34 | * Creates a new instance of AzureIdentityAccessTokenProvider. 35 | * @param tokenCredential The Azure.Identity.TokenCredential implementation to use. 36 | * @param allowedHosts The list of allowed hosts for which to request access tokens. 37 | * @param scopes The scopes to request access tokens for. 38 | * @param observabilityOptions The observability options to use. 39 | * @param isCaeEnabled Whether to enable Continuous Access Evaluation, defaults to true. 40 | */ 41 | @SuppressWarnings("LambdaLast") 42 | public AzureIdentityAccessTokenProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, 43 | @Nullable final ObservabilityOptions observabilityOptions, final boolean isCaeEnabled, @Nonnull final String... scopes) { 44 | super(tokenCredential, allowedHosts, observabilityOptions, isCaeEnabled, scopes); 45 | if (allowedHosts == null || allowedHosts.length == 0) { 46 | final HashSet allowedHostsSet = new HashSet(); 47 | allowedHostsSet.add("graph.microsoft.com"); 48 | allowedHostsSet.add("graph.microsoft.us"); 49 | allowedHostsSet.add("dod-graph.microsoft.us"); 50 | allowedHostsSet.add("graph.microsoft.de"); 51 | allowedHostsSet.add("microsoftgraph.chinacloudapi.cn"); 52 | allowedHostsSet.add("canary.graph.microsoft.com"); 53 | this.getAllowedHostsValidator().setAllowedHosts(allowedHostsSet); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/upload/UploadSessionRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.upload; 2 | 3 | import com.microsoft.graph.core.models.IUploadSession; 4 | import com.microsoft.graph.core.models.UploadResult; 5 | import com.microsoft.kiota.*; 6 | import com.microsoft.kiota.serialization.Parsable; 7 | import com.microsoft.kiota.serialization.ParsableFactory; 8 | import okhttp3.Response; 9 | 10 | import jakarta.annotation.Nonnull; 11 | import java.io.InputStream; 12 | import java.util.Objects; 13 | 14 | /** 15 | * UploadSessionRequestBuilder class to get and delete an UploadSession. 16 | * @param The type of object being uploaded. 17 | */ 18 | public class UploadSessionRequestBuilder { 19 | 20 | private final UploadResponseHandler responseHandler; 21 | private final RequestAdapter requestAdapter; 22 | private final String urlTemplate; 23 | private final ParsableFactory factory; 24 | /** 25 | * Create a new UploadSessionRequest. 26 | * @param sessionUrl The uploadSession url to use in the request. 27 | * @param requestAdapter The RequestAdapted to execute the request. 28 | * @param factory The ParsableFactory defining the instantiation of the object being uploaded. 29 | */ 30 | public UploadSessionRequestBuilder(@Nonnull String sessionUrl, 31 | @Nonnull final RequestAdapter requestAdapter, 32 | @Nonnull final ParsableFactory factory) { 33 | this.responseHandler = new UploadResponseHandler(); 34 | this.requestAdapter = Objects.requireNonNull(requestAdapter); 35 | if(Compatibility.isBlank(sessionUrl)) 36 | { 37 | throw new IllegalArgumentException("sessionUrl cannot be null or empty"); 38 | } 39 | this.urlTemplate = sessionUrl; 40 | this.factory = Objects.requireNonNull(factory); 41 | } 42 | /** 43 | * Gets the specified UploadSession. 44 | * @return the IUploadSession 45 | */ 46 | @Nonnull 47 | public IUploadSession get() { 48 | RequestInformation requestInformation = toGetRequestInformation(); 49 | NativeResponseHandler nativeResponseHandler = new NativeResponseHandler(); 50 | requestInformation.setResponseHandler(nativeResponseHandler); 51 | requestAdapter.sendPrimitive(requestInformation, null, InputStream.class); 52 | UploadResult result = responseHandler.handleResponse((Response) nativeResponseHandler.getValue(), factory); 53 | return result.uploadSession; 54 | } 55 | private RequestInformation toGetRequestInformation() { 56 | RequestInformation requestInformation = new RequestInformation(); 57 | requestInformation.httpMethod = HttpMethod.GET; 58 | requestInformation.urlTemplate = this.urlTemplate; 59 | return requestInformation; 60 | } 61 | /** 62 | * Deletes the specified UploadSession. 63 | */ 64 | public void delete() { 65 | RequestInformation requestInfo = this.toDeleteRequestInformation(); 66 | this.requestAdapter.sendPrimitive(requestInfo, null, Void.class); 67 | } 68 | private RequestInformation toDeleteRequestInformation() { 69 | RequestInformation requestInformation = new RequestInformation(); 70 | requestInformation.httpMethod = HttpMethod.DELETE; 71 | requestInformation.urlTemplate = this.urlTemplate; 72 | return requestInformation; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [main, support/2.x.x] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [main, support/2.x.x] 20 | schedule: 21 | - cron: '0 1 * * 4' 22 | workflow_dispatch: 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: 'ubuntu-latest' 28 | timeout-minutes: 10 29 | permissions: 30 | actions: read 31 | contents: read 32 | security-events: write 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | language: [ 'java' ] 38 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] 39 | # Use only 'java' to analyze code written in Java, Kotlin or both 40 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 41 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 42 | 43 | steps: 44 | - name: Checkout repository 45 | uses: actions/checkout@v5 46 | 47 | - name: Set up JDK 48 | uses: actions/setup-java@v5 49 | with: 50 | java-version: 21 51 | distribution: 'temurin' 52 | cache: gradle 53 | 54 | # Initializes the CodeQL tools for scanning. 55 | - name: Initialize CodeQL 56 | uses: github/codeql-action/init@v4 57 | with: 58 | languages: ${{ matrix.language }} 59 | # If you wish to specify custom queries, you can do so here or in a config file. 60 | # By default, queries listed here will override any specified in a config file. 61 | # Prefix the list here with "+" to use these queries and those in the config file. 62 | 63 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 64 | # queries: security-extended,security-and-quality 65 | 66 | 67 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). 68 | # If this step fails, then you should remove it and run the build manually (see below) 69 | # - name: Autobuild 70 | # uses: github/codeql-action/autobuild@v2 71 | 72 | # ℹ️ Command-line programs to run using the OS shell. 73 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 74 | 75 | # If the Autobuild fails above, remove it and uncomment the following three lines. 76 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 77 | 78 | - name: Grant execute permission for gradlew 79 | run: chmod +x gradlew 80 | - name: Build with Gradle 81 | run: ./gradlew build 82 | 83 | - name: Perform CodeQL Analysis 84 | uses: github/codeql-action/analyze@v4 85 | with: 86 | category: "/language:${{matrix.language}}" 87 | -------------------------------------------------------------------------------- /.github/workflows/project-auto-add.yml: -------------------------------------------------------------------------------- 1 | # This workflow is used to add new issues to GitHub GraphSDKs Project 2 | 3 | name: Add Issue or PR to project 4 | on: 5 | issues: 6 | types: 7 | - opened 8 | pull_request: 9 | types: 10 | - opened 11 | branches: 12 | - "main" 13 | 14 | jobs: 15 | track_issue: 16 | if: github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.fork == false 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Generate token 20 | id: generate_token 21 | uses: actions/create-github-app-token@v2 22 | with: 23 | app-id: ${{ secrets.GRAPHBOT_APP_ID }} 24 | private-key: ${{ secrets.GRAPHBOT_APP_PEM }} 25 | 26 | - name: Get project data 27 | env: 28 | GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} 29 | ORGANIZATION: microsoftgraph 30 | PROJECT_NUMBER: 55 31 | run: | 32 | gh api graphql -f query=' 33 | query($org: String!, $number: Int!) { 34 | organization(login: $org){ 35 | projectV2(number: $number) { 36 | id 37 | fields(first:20) { 38 | nodes { 39 | ... on ProjectV2SingleSelectField { 40 | id 41 | name 42 | options { 43 | id 44 | name 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json 52 | 53 | echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV 54 | echo 'LANGUAGE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Language") | .id' project_data.json) >> $GITHUB_ENV 55 | echo 'LANGUAGE_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Language") | .options[] | select(.name=="Java") |.id' project_data.json) >> $GITHUB_ENV 56 | 57 | - name: Add Issue or PR to project 58 | env: 59 | GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} 60 | ISSUE_ID: ${{ github.event_name == 'issues' && github.event.issue.node_id || github.event.pull_request.node_id }} 61 | run: | 62 | item_id="$( gh api graphql -f query=' 63 | mutation($project:ID!, $issue:ID!) { 64 | addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) { 65 | item { 66 | id 67 | } 68 | } 69 | }' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectV2ItemById.item.id')" 70 | 71 | echo 'ITEM_ID='$item_id >> $GITHUB_ENV 72 | 73 | - name: Set Language 74 | env: 75 | GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} 76 | run: | 77 | gh api graphql -f query=' 78 | mutation ( 79 | $project: ID! 80 | $item: ID! 81 | $language_field: ID! 82 | $language_value: String! 83 | ) { 84 | set_status: updateProjectV2ItemFieldValue(input: { 85 | projectId: $project 86 | itemId: $item 87 | fieldId: $language_field 88 | value: {singleSelectOptionId: $language_value} 89 | }) { 90 | projectV2Item { 91 | id 92 | } 93 | } 94 | }' -f project=$PROJECT_ID -f item=$ITEM_ID -f language_field=$LANGUAGE_FIELD_ID -f language_value=${{ env.LANGUAGE_OPTION_ID }} --silent 95 | -------------------------------------------------------------------------------- /.github/policies/resourceManagement.yml: -------------------------------------------------------------------------------- 1 | id: 2 | name: GitOps.PullRequestIssueManagement 3 | description: GitOps.PullRequestIssueManagement primitive 4 | owner: 5 | resource: repository 6 | disabled: false 7 | where: 8 | configuration: 9 | resourceManagementConfiguration: 10 | scheduledSearches: 11 | - description: 12 | frequencies: 13 | - hourly: 14 | hour: 6 15 | filters: 16 | - isIssue 17 | - isOpen 18 | - hasLabel: 19 | label: 'Needs: author feedback' 20 | - hasLabel: 21 | label: no-recent-activity 22 | - noActivitySince: 23 | days: 3 24 | - isNotLabeledWith: 25 | label: service bug 26 | actions: 27 | - closeIssue 28 | - description: 29 | frequencies: 30 | - hourly: 31 | hour: 6 32 | filters: 33 | - isIssue 34 | - isOpen 35 | - hasLabel: 36 | label: 'Needs: author feedback' 37 | - noActivitySince: 38 | days: 4 39 | - isNotLabeledWith: 40 | label: no-recent-activity 41 | actions: 42 | - addLabel: 43 | label: no-recent-activity 44 | - addReply: 45 | reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. 46 | - description: 47 | frequencies: 48 | - hourly: 49 | hour: 6 50 | filters: 51 | - isIssue 52 | - isOpen 53 | - hasLabel: 54 | label: duplicate 55 | - noActivitySince: 56 | days: 1 57 | actions: 58 | - addReply: 59 | reply: This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes. 60 | - closeIssue 61 | eventResponderTasks: 62 | - if: 63 | - payloadType: Issues 64 | - isAction: 65 | action: Closed 66 | - hasLabel: 67 | label: 'status:waiting-for-author-feedback' 68 | then: 69 | - removeLabel: 70 | label: 'status:waiting-for-author-feedback' 71 | description: 72 | - if: 73 | - payloadType: Issue_Comment 74 | - isAction: 75 | action: Created 76 | - isActivitySender: 77 | issueAuthor: True 78 | - hasLabel: 79 | label: 'Needs: author feedback' 80 | then: 81 | - addLabel: 82 | label: needs attention 83 | - removeLabel: 84 | label: 'Needs: author feedback' 85 | description: 86 | - if: 87 | - payloadType: Issues 88 | - not: 89 | isAction: 90 | action: Closed 91 | - hasLabel: 92 | label: no-recent-activity 93 | then: 94 | - removeLabel: 95 | label: no-recent-activity 96 | description: 97 | - if: 98 | - payloadType: Issues 99 | - labelAdded: 100 | label: service bug 101 | then: [] 102 | description: 103 | - if: 104 | - payloadType: Issue_Comment 105 | - activitySenderHasAssociation: 106 | association: Contributor 107 | - bodyContains: 108 | pattern: '?' 109 | isRegex: False 110 | - bodyContains: 111 | pattern: '@' 112 | isRegex: False 113 | then: 114 | - addLabel: 115 | label: 'Needs: author feedback' 116 | description: 117 | - if: 118 | - payloadType: Issues 119 | - or: 120 | - isAssignedToSomeone 121 | - isAction: 122 | action: Closed 123 | then: 124 | - removeLabel: 125 | label: ToTriage 126 | description: 127 | onFailure: 128 | onSuccess: 129 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01-sdk-bug.yml: -------------------------------------------------------------------------------- 1 | name: SDK Bug Report 2 | description: File SDK bug report 3 | labels: ["type:bug", "status:waiting-for-triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | **Thank you for taking the time to fill out this bug report!** 9 | 💥Before submitting a new request, please search existing issues to see if an issue already exists. 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Describe the bug 14 | description: | 15 | Provide a description of the actual behavior observed. If applicable please include any error messages, exception stacktraces or a screenshot. 16 | placeholder: I am trying to do [...] but [...] 17 | validations: 18 | required: true 19 | - type: textarea 20 | id: expected-behavior 21 | attributes: 22 | label: Expected behavior 23 | description: | 24 | A clear and concise description of what you expected to happen. 25 | placeholder: Expected behavior 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: repro-steps 30 | attributes: 31 | label: How to reproduce 32 | description: | 33 | Please include minimal steps to reproduce the problem if possible. E.g.: the smallest possible code snippet; or steps to run project in link above. If possible include text as text rather than screenshots (so it shows up in searches). 34 | If there's a link to a public repo where the sample code exists, include it too. 35 | placeholder: Minimal Reproduction steps 36 | validations: 37 | required: true 38 | - type: input 39 | attributes: 40 | label: SDK Version 41 | placeholder: e.g. 5.32.1 42 | description: Version of the SDK with the bug described above. 43 | validations: 44 | required: false 45 | - type: input 46 | id: regression 47 | attributes: 48 | label: Latest version known to work for scenario above? 49 | description: | 50 | Did this work in a previous build or release of the SDK or API client? If you can try a previous release or build to find out, that can help us narrow down the problem. If you don't know, that's OK. 51 | placeholder: version-number 52 | validations: 53 | required: false 54 | - type: textarea 55 | id: known-workarounds 56 | attributes: 57 | label: Known Workarounds 58 | description: | 59 | Please provide a description of any known workarounds. 60 | placeholder: Known Workarounds 61 | validations: 62 | required: false 63 | - type: textarea 64 | id: logs 65 | attributes: 66 | label: Debug output 67 | description: Please copy and paste the debug output below. 68 | value: | 69 |
Click to expand log 70 | ``` 71 | 72 | 73 | 74 | ``` 75 |
76 | validations: 77 | required: false 78 | - type: textarea 79 | id: configuration 80 | attributes: 81 | label: Configuration 82 | description: | 83 | Please provide more information on your SDK configuration: 84 | * What OS and version, and what distro if applicable (Windows 10, Windows 11, MacOS Catalina, Ubuntu 22.04)? 85 | * What is the architecture (x64, x86, ARM, ARM64)? 86 | * Do you know whether it is specific to that configuration? 87 | placeholder: | 88 | - OS: 89 | - architecture: 90 | validations: 91 | required: false 92 | - type: textarea 93 | id: other-info 94 | attributes: 95 | label: Other information 96 | description: | 97 | If you have an idea where the problem might lie, let us know that here. Please include any pointers to code, relevant changes, or related issues you know of. 98 | placeholder: Other information 99 | validations: 100 | required: false 101 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/BatchRequestBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import com.microsoft.graph.core.BaseClient; 4 | import com.microsoft.graph.core.CoreConstants; 5 | import com.microsoft.graph.core.content.BatchRequestContent; 6 | import com.microsoft.graph.core.models.BatchRequestStep; 7 | import com.microsoft.kiota.HttpMethod; 8 | import com.microsoft.kiota.RequestInformation; 9 | import com.microsoft.kiota.authentication.AnonymousAuthenticationProvider; 10 | import okhttp3.MediaType; 11 | import okhttp3.Request; 12 | import okhttp3.RequestBody; 13 | import org.junit.jupiter.api.Test; 14 | 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.net.URI; 18 | import java.nio.charset.StandardCharsets; 19 | import java.util.ArrayList; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | import java.io.ByteArrayInputStream; 23 | 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | import static org.junit.jupiter.api.Assertions.assertNotNull; 26 | 27 | class BatchRequestBuilderTest { 28 | 29 | @Test 30 | void BatchRequestBuilder_DefaultBuilderTest() throws IOException { 31 | BaseClient client = new BaseClient(new AnonymousAuthenticationProvider(), "https://localhost"); 32 | BatchRequestBuilder batchRequestBuilder = new BatchRequestBuilder(client.getRequestAdapter()); 33 | 34 | Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build(); 35 | RequestBody requestBody = RequestBody.create("{}", MediaType.get(CoreConstants.MimeTypeNames.APPLICATION_JSON)); 36 | Request request2 = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/onenote/notebooks").post(requestBody).build(); 37 | BatchRequestStep batchRequestStep = new BatchRequestStep("1", request); 38 | BatchRequestStep batchRequestStep2 = new BatchRequestStep("2", request2, Arrays.asList("1")); 39 | 40 | BatchRequestContent batchRequestContent = new BatchRequestContent(client,Arrays.asList(batchRequestStep, batchRequestStep2)); 41 | RequestInformation requestInformation = batchRequestBuilder.toPostRequestInformation(batchRequestContent); 42 | 43 | assertEquals("{+baseurl}/$batch", requestInformation.urlTemplate); 44 | assertEquals(client.getRequestAdapter(), batchRequestBuilder.getRequestAdapter()); 45 | 46 | } 47 | @Test 48 | void BatchContentDoesNotDeadlockOnLargeContent() throws IOException { 49 | final BaseClient client = new BaseClient(new AnonymousAuthenticationProvider(), "https://localhost"); 50 | final BatchRequestContent batchRequestContent = new BatchRequestContent(client); 51 | final List streamsToClose = new ArrayList<>(); 52 | for (int i = 0; i < 20; i++) { 53 | final RequestInformation requestInformation = new RequestInformation(); 54 | requestInformation.httpMethod = HttpMethod.POST; 55 | requestInformation.setUri(URI.create("https://graph.microsoft.com/v1.0/me/")); 56 | final String payload = "{\"displayName\": \"Test\", \"lastName\": \"User\", \"mailNickname\": \"testuser\", \"userPrincipalName\": \"testUser\", \"passwordProfile\": {\"forceChangePasswordNextSignIn\": true, \"password\": \"password\"}, \"accountEnabled\": true}"; 57 | final InputStream content = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8)); 58 | streamsToClose.add(content); 59 | requestInformation.setStreamContent(content, CoreConstants.MimeTypeNames.APPLICATION_JSON); 60 | batchRequestContent.addBatchRequestStep(requestInformation); 61 | } 62 | BatchRequestBuilder batchRequestBuilder = new BatchRequestBuilder(client.getRequestAdapter()); 63 | RequestInformation requestInformation = batchRequestBuilder.toPostRequestInformation(batchRequestContent); 64 | assertNotNull(requestInformation); 65 | for (final InputStream inputStream : streamsToClose) { 66 | inputStream.close(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/models/TokenValidableTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import com.microsoft.graph.core.testModels.TestChangeNotification; 4 | import com.microsoft.graph.core.testModels.TestChangeNotificationCollection; 5 | import com.microsoft.graph.core.testModels.TestChangeNotificationEncryptedContent; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.UUID; 11 | 12 | import static org.junit.jupiter.api.Assertions.*; 13 | 14 | public class TokenValidableTests { 15 | @Test 16 | void TestTokenValidWithNoValidationTokens() { 17 | var testChangeNotification = new TestChangeNotificationCollection (); 18 | var tenantIds = new ArrayList(); 19 | var appIds = new ArrayList(); 20 | var result = TokenValidable.areTokensValid(testChangeNotification,tenantIds,appIds); 21 | assertTrue(result); 22 | } 23 | 24 | @Test 25 | void TestTokenValidWithNoEncryptedData() { 26 | var testChangeNotificationCollection = new TestChangeNotificationCollection (); 27 | var testTokens = new ArrayList(); 28 | testTokens.add("testToken"); 29 | testChangeNotificationCollection.setValidationTokens(testTokens); 30 | var testNotifications = new ArrayList(); 31 | var testChangeNotification = new TestChangeNotification(); 32 | testNotifications.add(testChangeNotification); 33 | testChangeNotificationCollection.setValue(testNotifications); 34 | var tenantIds = new ArrayList(); 35 | var appIds = new ArrayList(); 36 | var result = TokenValidable.areTokensValid(testChangeNotificationCollection,tenantIds,appIds); 37 | assertTrue(result); // no encrypted content 38 | } 39 | @Test 40 | void TestTokenValidWithEncryptedDataAndNoParameters() { 41 | var testChangeNotificationCollection = new TestChangeNotificationCollection (); 42 | var testTokens = new ArrayList(); 43 | testTokens.add("testToken"); 44 | testChangeNotificationCollection.setValidationTokens(testTokens); 45 | var testNotifications = new ArrayList(); 46 | var testChangeNotification = new TestChangeNotification(); 47 | var testEncryptedContent = new TestChangeNotificationEncryptedContent(); 48 | testChangeNotification.setEncryptedContent(testEncryptedContent); 49 | testNotifications.add(testChangeNotification); 50 | testChangeNotificationCollection.setValue(testNotifications); 51 | var tenantIds = new ArrayList(); 52 | var appIds = new ArrayList(); 53 | assertThrows(IllegalArgumentException.class,() -> TokenValidable.areTokensValid(testChangeNotificationCollection,tenantIds,appIds)); 54 | } 55 | 56 | @Test 57 | void TestTokenValidWithEncryptedData() { 58 | var testChangeNotificationCollection = new TestChangeNotificationCollection (); 59 | var testTokens = new ArrayList(); 60 | testTokens.add("testToken"); 61 | testChangeNotificationCollection.setValidationTokens(testTokens); 62 | var testNotifications = new ArrayList(); 63 | var testChangeNotification = new TestChangeNotification(); 64 | var testEncryptedContent = new TestChangeNotificationEncryptedContent(); 65 | testChangeNotification.setEncryptedContent(testEncryptedContent); 66 | testNotifications.add(testChangeNotification); 67 | testChangeNotificationCollection.setValue(testNotifications); 68 | var tenantIds = new ArrayList(); 69 | tenantIds.add(UUID.randomUUID()); 70 | var appIds = new ArrayList(); 71 | appIds.add(UUID.randomUUID()); 72 | var exception = assertThrows(IllegalArgumentException.class,() -> TokenValidable.areTokensValid(testChangeNotificationCollection,tenantIds,appIds)); 73 | assertEquals("Invalid token",exception.getMessage()); // issuer for the token is invalid 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Microsoft Graph Core SDK for Java 2 | 3 | The Microsoft Graph Core SDK for Java is available for all manner of contribution. There are a couple of different recommended paths to get contributions into the released version of this SDK. 4 | 5 | __NOTE__ A signed a contribution license agreement is required for all contributions, and is checked automatically on new pull requests. Please read and sign the agreement https://cla.microsoft.com/ before starting any work for this repository. 6 | 7 | ## File issues 8 | 9 | The best way to get started with a contribution is to start a dialog with the owners of this repository. Sometimes features will be under development or out of scope for this SDK and it's best to check before starting work on contribution. 10 | 11 | ## Submit pull requests for trivial changes 12 | 13 | If you are making a change that does not affect the interface components and does not affect other downstream callers, feel free to make a pull request against the __main__ branch. The main branch will be updated frequently. 14 | 15 | Revisions of this nature will result in a 0.0.X change of the version number. 16 | 17 | ## Submit pull requests for features 18 | 19 | If major functionality is being added, or there will need to be gestation time for a change, it should be submitted against the __feature__ branch. 20 | 21 | Revisions of this nature will result in a 0.X.X change of the version number. 22 | 23 | ## Commit message format 24 | 25 | To support our automated release process, pull requests are required to follow the [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) 26 | format. 27 | 28 | Each commit message consists of a **header**, an optional **body** and an optional **footer**. The header is the first line of the commit and 29 | MUST have a **type** (see below for a list of types) and a **description**. An optional **scope** can be added to the header to give extra context. 30 | 31 | ``` 32 | [optional scope]: 33 | 34 | 35 | 36 | 37 | ``` 38 | 39 | The recommended commit types used are: 40 | 41 | - **feat** for feature updates (increments the _minor_ version) 42 | - **fix** for bug fixes (increments the _patch_ version) 43 | - **perf** for performance related changes e.g. optimizing an algorithm 44 | - **refactor** for code refactoring changes 45 | - **test** for test suite updates e.g. adding a test or fixing a test 46 | - **style** for changes that don't affect the meaning of code. e.g. formatting changes 47 | - **docs** for documentation updates e.g. ReadMe update or code documentation updates 48 | - **build** for build system changes (gradle updates, external dependency updates) 49 | - **ci** for CI configuration file changes e.g. updating a pipeline 50 | - **chore** for miscallaneous non-sdk changesin the repo e.g. removing an unused file 51 | 52 | Adding a footer with the prefix **BREAKING CHANGE:** will cause an increment of the _major_ version. 53 | 54 | ## Add yourself as a contributor 55 | 56 | This project follows the [all contributors](https://github.com/kentcdodds/all-contributors) specification. When making a contribution, please add yourself to the table of contributors: 57 | 58 | 1. In section 5. of the [README.md](https://github.com/microsoftgraph/msgraph-sdk-java-core/blob/main/readme.md), after the last "|", copy and paste a new blank contributor element 59 | ```html 60 | [
61 | Your Name](your website or github page)
62 | [emoji](link "alt-text") | 63 | ``` 64 | 65 | You can get your GitHub UID by inspecting your GitHub avatar image. 66 | 67 | 2. For each contribution type (see [emoji key](https://github.com/kentcdodds/all-contributors#emoji-key) for a list of contribution types), add an emoji and a relevant link and alt-text. 68 | 69 | For example, if you write a blogpost on how to use the SDK, you would include: 70 | 71 | ```html 72 | [??]("https://myblog.com/using-the-java-sdk" "Blog Post") 73 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/models/BatchRequestStep.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.models; 2 | 3 | import com.microsoft.graph.core.CoreConstants; 4 | import com.microsoft.graph.core.ErrorConstants; 5 | import com.microsoft.kiota.Compatibility; 6 | import com.microsoft.kiota.http.middleware.UrlReplaceHandler; 7 | import okhttp3.Request; 8 | 9 | import jakarta.annotation.Nonnull; 10 | import java.util.*; 11 | 12 | /** 13 | * Represents a single request in a batch request 14 | */ 15 | public class BatchRequestStep { 16 | 17 | private final String requestId; 18 | private final Request request; 19 | private List dependsOn; 20 | /** 21 | * Creates a new BatchRequestStep 22 | * @param requestId The id of the request 23 | * @param request The request 24 | */ 25 | public BatchRequestStep(@Nonnull String requestId, @Nonnull Request request) { 26 | Objects.requireNonNull(request, ErrorConstants.Messages.NULL_PARAMETER + "request"); 27 | if(Compatibility.isBlank(requestId)) { 28 | throw new IllegalArgumentException("requestId cannot be null or empty."); 29 | } 30 | this.requestId = requestId; 31 | this.request = UrlReplaceHandler.replaceRequestUrl(request, CoreConstants.ReplacementConstants.getDefaultReplacementPairs()); 32 | } 33 | /** 34 | * Creates a new BatchRequestStep 35 | * @param requestId The id of the request 36 | * @param request The request 37 | * @param dependsOn The ids of the requests that this request depends on 38 | */ 39 | public BatchRequestStep(@Nonnull String requestId, @Nonnull Request request, @Nonnull List dependsOn) { 40 | this(requestId, request); 41 | this.dependsOn = new ArrayList<>(dependsOn); 42 | } 43 | /** 44 | * Gets the request 45 | * @return The request 46 | */ 47 | @Nonnull 48 | public Request getRequest() { 49 | return this.request; 50 | } 51 | /** 52 | * Gets the id of the request 53 | * @return The id of the request 54 | */ 55 | @Nonnull 56 | public String getRequestId() { 57 | return this.requestId; 58 | } 59 | /** 60 | * Gets the ids of the requests that this request depends on 61 | * @return The ids of the requests that this request depends on 62 | */ 63 | @Nonnull 64 | public List getDependsOn() { 65 | if(dependsOn == null) { 66 | return new ArrayList<>(); 67 | } 68 | return new ArrayList<>(dependsOn); 69 | } 70 | /** 71 | * Sets the ids of the requests that this request depends on 72 | * @param dependsOn The ids of the requests that this request depends on 73 | */ 74 | public void setDependsOn(@Nonnull List dependsOn) { 75 | this.dependsOn = new ArrayList<>(dependsOn); 76 | } 77 | /** 78 | * Adds a request id to the dependsOn list. 79 | * @param id The id of the request to add to the dependsOn list. 80 | */ 81 | public void addDependsOnId(@Nonnull String id) { 82 | if(Compatibility.isBlank(id)) { 83 | throw new IllegalArgumentException("id cannot be null or empty"); 84 | } 85 | if(dependsOn == null) { 86 | dependsOn = new ArrayList<>(); 87 | } 88 | dependsOn.add(id); 89 | } 90 | /** 91 | * Removes a request id from the dependsOn list. 92 | * 93 | * @param id The id of the request to remove. 94 | * @return true if the request id is no longer present in the dependsOn collection, false if dependsOn is null. 95 | */ 96 | public boolean removeDependsOnId(@Nonnull String id) { 97 | Objects.requireNonNull(id); 98 | if(dependsOn != null) { 99 | if(!dependsOn.contains(id) || id.isEmpty()) { 100 | throw new IllegalArgumentException("id is not present in the dependsOn collection or is empty"); 101 | } 102 | dependsOn.removeAll(Collections.singleton(id)); 103 | return true; 104 | } 105 | return false; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/upload/UploadSliceRequestTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.upload; 2 | 3 | import com.microsoft.graph.core.CoreConstants; 4 | import com.microsoft.graph.core.models.UploadResult; 5 | import com.microsoft.graph.core.models.UploadSession; 6 | import com.microsoft.graph.core.testModels.TestDriveItem; 7 | import com.microsoft.kiota.authentication.AnonymousAuthenticationProvider; 8 | import com.microsoft.kiota.http.OkHttpRequestAdapter; 9 | import com.microsoft.kiota.serialization.JsonParseNodeFactory; 10 | import com.microsoft.kiota.serialization.ParsableFactory; 11 | import com.microsoft.kiota.serialization.ParseNodeFactoryRegistry; 12 | import okhttp3.*; 13 | import org.junit.jupiter.api.Test; 14 | import org.mockito.stubbing.Answer; 15 | 16 | import java.io.ByteArrayInputStream; 17 | import java.io.IOException; 18 | import java.net.HttpURLConnection; 19 | import java.time.OffsetDateTime; 20 | 21 | import static com.microsoft.kiota.serialization.ParseNodeFactoryRegistry.defaultInstance; 22 | import static org.junit.jupiter.api.Assertions.*; 23 | import static org.mockito.Mockito.*; 24 | 25 | class UploadSliceRequestTest { 26 | ParseNodeFactoryRegistry registry = defaultInstance; 27 | 28 | @Test 29 | void putReturnsExpectedUploadSession() throws IOException { 30 | registry.contentTypeAssociatedFactories.put(CoreConstants.MimeTypeNames.APPLICATION_JSON, new JsonParseNodeFactory()); 31 | ParsableFactory factory = TestDriveItem::createFromDiscriminatorValue; 32 | ResponseBody body = ResponseBody.create( 33 | "{\n" + 34 | " \"expirationDateTime\": \"2015-01-29T09:21:55.523Z\",\n" + 35 | " \"nextExpectedRanges\": [\n" + 36 | " \"12345-55232\",\n" + 37 | " \"77829-99375\"\n" + 38 | " ]" + 39 | "}", MediaType.parse(CoreConstants.MimeTypeNames.APPLICATION_JSON)); 40 | Response response = new Response.Builder() 41 | .request(new Request.Builder().post(mock(RequestBody.class)).url("https://a.b.c/").build()) 42 | .protocol(Protocol.HTTP_1_1) 43 | .message("Accepted") 44 | .body(body) 45 | .code(HttpURLConnection.HTTP_ACCEPTED) 46 | .build(); 47 | 48 | OkHttpClient mockClient = getMockClient(response); 49 | final OkHttpRequestAdapter adapter = 50 | new OkHttpRequestAdapter(new AnonymousAuthenticationProvider(), null, null,mockClient); 51 | 52 | byte[] mockData = new byte[500]; 53 | ByteArrayInputStream stream = new ByteArrayInputStream(mockData); 54 | 55 | UploadSliceRequestBuilder sliceRequestBuilder = new UploadSliceRequestBuilder<>( 56 | "https://a.b.c/", adapter, 0, 200 , 1000, factory); 57 | 58 | UploadResult result = sliceRequestBuilder.put(stream); 59 | UploadSession session = (UploadSession) result.uploadSession; 60 | 61 | assertFalse(result.isUploadSuccessful()); 62 | assertNotNull(session); 63 | assertTrue(session.getUploadUrl().isEmpty()); 64 | assertEquals(OffsetDateTime.parse("2015-01-29T09:21:55.523Z"), session.getExpirationDateTime()); 65 | assertEquals("12345-55232", session.getNextExpectedRanges().get(0)); 66 | assertEquals("77829-99375", session.getNextExpectedRanges().get(1)); 67 | assertEquals(2, session.getNextExpectedRanges().size()); 68 | } 69 | 70 | public static OkHttpClient getMockClient(final Response response) throws IOException { 71 | final OkHttpClient mockClient = mock(OkHttpClient.class); 72 | final Call remoteCall = mock(Call.class); 73 | final Dispatcher dispatcher = new Dispatcher(); 74 | when(remoteCall.execute()).thenReturn(response); 75 | doAnswer((Answer) invocation -> { 76 | Callback callback = invocation.getArgument(0); 77 | callback.onResponse(null, response); 78 | return null; 79 | }).when(remoteCall).enqueue(any(Callback.class)); 80 | when(mockClient.dispatcher()).thenReturn(dispatcher); 81 | when(mockClient.newCall(any())).thenReturn(remoteCall); 82 | return mockClient; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /spotBugsExcludeFilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/BaseCollectionPaginationCountResponse.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | 7 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 8 | import com.microsoft.kiota.serialization.Parsable; 9 | import com.microsoft.kiota.serialization.ParseNode; 10 | import com.microsoft.kiota.serialization.SerializationWriter; 11 | 12 | public class BaseCollectionPaginationCountResponse implements AdditionalDataHolder, Parsable { 13 | public Map additionalData; 14 | private String odataNextLink; 15 | private Long odataCount; 16 | /** 17 | * Instantiates a new BaseCollectionPaginationCountResponse and sets the default values. 18 | */ 19 | public BaseCollectionPaginationCountResponse() { 20 | this.setAdditionalData(new HashMap<>()); 21 | } 22 | /** 23 | * Creates a new instance of the appropriate class based on discriminator value 24 | * @param parseNode The parse node to use to read the discriminator value and create the object 25 | * @return a BaseCollectionPaginationCountResponse 26 | */ 27 | @jakarta.annotation.Nonnull 28 | public static BaseCollectionPaginationCountResponse createFromDiscriminatorValue(@jakarta.annotation.Nonnull final ParseNode parseNode) { 29 | Objects.requireNonNull(parseNode); 30 | return new BaseCollectionPaginationCountResponse(); 31 | } 32 | /** 33 | * Gets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. 34 | * @return a Map 35 | */ 36 | @jakarta.annotation.Nonnull 37 | public Map getAdditionalData() { 38 | return this.additionalData; 39 | } 40 | /** 41 | * The deserialization information for the current model 42 | * @return a Map> 43 | */ 44 | @jakarta.annotation.Nonnull 45 | public Map> getFieldDeserializers() { 46 | final HashMap> deserializerMap = new HashMap>(2); 47 | deserializerMap.put("@odata.count", (n) -> { this.setOdataCount(n.getLongValue()); }); 48 | deserializerMap.put("@odata.nextLink", (n) -> { this.setOdataNextLink(n.getStringValue()); }); 49 | return deserializerMap; 50 | } 51 | /** 52 | * Gets the @odata.count property value. The OdataCount property 53 | * @return a Long 54 | */ 55 | @jakarta.annotation.Nullable 56 | public Long getOdataCount() { 57 | return this.odataCount; 58 | } 59 | /** 60 | * Gets the @odata.nextLink property value. The OdataNextLink property 61 | * @return a String 62 | */ 63 | @jakarta.annotation.Nullable 64 | public String getOdataNextLink() { 65 | return this.odataNextLink; 66 | } 67 | /** 68 | * Serializes information the current object 69 | * @param writer Serialization writer to use to serialize this model 70 | */ 71 | public void serialize(@jakarta.annotation.Nonnull final SerializationWriter writer) { 72 | Objects.requireNonNull(writer); 73 | writer.writeLongValue("@odata.count", this.getOdataCount()); 74 | writer.writeStringValue("@odata.nextLink", this.getOdataNextLink()); 75 | writer.writeAdditionalData(this.getAdditionalData()); 76 | } 77 | /** 78 | * Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. 79 | * @param value Value to set for the AdditionalData property. 80 | */ 81 | public void setAdditionalData(@jakarta.annotation.Nullable final Map value) { 82 | this.additionalData = value; 83 | } 84 | /** 85 | * Sets the @odata.count property value. The OdataCount property 86 | * @param value Value to set for the @odata.count property. 87 | */ 88 | public void setOdataCount(@jakarta.annotation.Nullable final Long value) { 89 | this.odataCount = value; 90 | } 91 | /** 92 | * Sets the @odata.nextLink property value. The OdataNextLink property 93 | * @param value Value to set for the @odata.nextLink property. 94 | */ 95 | public void setOdataNextLink(@jakarta.annotation.Nullable final String value) { 96 | this.odataNextLink = value; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestEvent.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.Objects; 12 | import java.util.function.Consumer; 13 | 14 | public class TestEvent implements Parsable, AdditionalDataHolder { 15 | private String id; 16 | private String oDataType; 17 | private HashMap additionalData; 18 | private String subject; 19 | private TestItemBody body; 20 | private TestDateTimeTimeZone end; 21 | private TestDateTimeTimeZone start; 22 | private ArrayList attendees; 23 | 24 | public TestEvent() { 25 | this.oDataType = "microsoft.graph.event"; 26 | } 27 | 28 | public String getId() { 29 | return id; 30 | } 31 | 32 | public void setId(String id) { 33 | this.id = id; 34 | } 35 | 36 | public String getODataType() { 37 | return oDataType; 38 | } 39 | 40 | public void setODataType(String oDataType) { 41 | this.oDataType = oDataType; 42 | } 43 | 44 | @Nonnull 45 | public HashMap getAdditionalData() { 46 | return additionalData; 47 | } 48 | 49 | public void setAdditionalData(HashMap additionalData) { 50 | this.additionalData = additionalData; 51 | } 52 | 53 | public String getSubject() { 54 | return subject; 55 | } 56 | 57 | public void setSubject(String subject) { 58 | this.subject = subject; 59 | } 60 | 61 | public TestItemBody getBody() { 62 | return body; 63 | } 64 | 65 | public void setBody(TestItemBody body) { 66 | this.body = body; 67 | } 68 | 69 | public TestDateTimeTimeZone getEnd() { 70 | return end; 71 | } 72 | 73 | public void setEnd(TestDateTimeTimeZone end) { 74 | this.end = end; 75 | } 76 | 77 | public TestDateTimeTimeZone getStart() { 78 | return start; 79 | } 80 | 81 | public void setStart(TestDateTimeTimeZone start) { 82 | this.start = start; 83 | } 84 | 85 | public ArrayList getAttendees() { 86 | return attendees; 87 | } 88 | 89 | public void setAttendees(ArrayList attendees) { 90 | this.attendees = attendees; 91 | } 92 | 93 | public HashMap> getFieldDeserializers() { 94 | HashMap> fieldDeserializers = new HashMap<>(); 95 | fieldDeserializers.put("@odata.type", (n) -> { setODataType(n.getStringValue()); }); 96 | fieldDeserializers.put("id", (n) -> { setId(n.getStringValue()); }); 97 | fieldDeserializers.put("subject", (n) -> { setSubject(n.getStringValue()); }); 98 | fieldDeserializers.put("body", (n) -> { setBody(n.getObjectValue(TestItemBody::createFromDiscriminatorValue)); }); 99 | fieldDeserializers.put("end", (n) -> { setEnd(n.getObjectValue(TestDateTimeTimeZone::createFromDiscriminatorValue)); }); 100 | fieldDeserializers.put("start", (n) -> { setStart(n.getObjectValue(TestDateTimeTimeZone::createFromDiscriminatorValue)); }); 101 | fieldDeserializers.put("attendees", (n) -> { setAttendees((ArrayList) n.getCollectionOfObjectValues(TestAttendee::createFromDiscriminatorValue)); }); 102 | return fieldDeserializers; 103 | } 104 | 105 | public void serialize(SerializationWriter writer) { 106 | Objects.requireNonNull(writer); 107 | writer.writeStringValue("@odata.type", getODataType()); 108 | writer.writeStringValue("id", getId()); 109 | writer.writeStringValue("subject", getSubject()); 110 | writer.writeObjectValue("body", getBody()); 111 | writer.writeObjectValue("end", getEnd()); 112 | writer.writeObjectValue("start", getStart()); 113 | writer.writeCollectionOfObjectValues("attendees", getAttendees()); 114 | writer.writeAdditionalData(getAdditionalData()); 115 | } 116 | 117 | public static TestEvent createFromDiscriminatorValue(ParseNode parseNode) { 118 | if (parseNode == null) { 119 | throw new IllegalArgumentException("The parseNode cannot be null."); 120 | } 121 | return new TestEvent(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestUser.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.function.Consumer; 12 | 13 | public class TestUser implements Parsable, AdditionalDataHolder { 14 | private String id; 15 | private String oDataType; 16 | private HashMap additionalData; 17 | private String givenName; 18 | private String displayName; 19 | private String state; 20 | private String surname; 21 | private List eventDeltas; 22 | 23 | public TestUser() { 24 | this.oDataType = "microsoft.graph.user"; 25 | } 26 | 27 | public String getId() { 28 | return id; 29 | } 30 | 31 | public void setId(String id) { 32 | this.id = id; 33 | } 34 | 35 | public String getODataType() { 36 | return oDataType; 37 | } 38 | 39 | public void setODataType(String oDataType) { 40 | this.oDataType = oDataType; 41 | } 42 | 43 | public HashMap getAdditionalData() { 44 | return additionalData; 45 | } 46 | 47 | public void setAdditionalData(HashMap additionalData) { 48 | this.additionalData = additionalData; 49 | } 50 | 51 | public String getGivenName() { 52 | return givenName; 53 | } 54 | 55 | public void setGivenName(String givenName) { 56 | this.givenName = givenName; 57 | } 58 | 59 | public String getDisplayName() { 60 | return displayName; 61 | } 62 | 63 | public void setDisplayName(String displayName) { 64 | this.displayName = displayName; 65 | } 66 | 67 | public String getState() { 68 | return state; 69 | } 70 | 71 | public void setState(String state) { 72 | this.state = state; 73 | } 74 | 75 | public String getSurname() { 76 | return surname; 77 | } 78 | 79 | public void setSurname(String surname) { 80 | this.surname = surname; 81 | } 82 | 83 | public List getEventDeltas() { 84 | return eventDeltas; 85 | } 86 | 87 | public void setEventDeltas(List eventDeltas) { 88 | this.eventDeltas = eventDeltas; 89 | } 90 | 91 | public HashMap> getFieldDeserializers() { 92 | final HashMap> deserializerMap = new HashMap>(); 93 | deserializerMap.put("id", (n) -> { setId(n.getStringValue()); }); 94 | deserializerMap.put("@odata.type", (n) -> { setODataType(n.getStringValue()); }); 95 | deserializerMap.put("givenName", (n) -> { setGivenName(n.getStringValue()); }); 96 | deserializerMap.put("displayName", (n) -> { setDisplayName(n.getStringValue()); }); 97 | deserializerMap.put("state", (n) -> { setState(n.getStringValue()); }); 98 | deserializerMap.put("surname", (n) -> { setSurname(n.getStringValue()); }); 99 | deserializerMap.put("eventDeltas", (n) -> { 100 | ArrayList eventList = new ArrayList<>(); 101 | for (TestEvent item : n.getCollectionOfObjectValues(TestEvent::createFromDiscriminatorValue)) { 102 | eventList.add(item); 103 | } 104 | setEventDeltas(eventList); 105 | }); 106 | return deserializerMap; 107 | } 108 | 109 | public void serialize(SerializationWriter writer) { 110 | if (writer == null) { 111 | throw new IllegalArgumentException("writer cannot be null"); 112 | } 113 | writer.writeStringValue("id", id); 114 | writer.writeStringValue("@odata.type", oDataType); 115 | writer.writeStringValue("givenName", givenName); 116 | writer.writeStringValue("displayName", displayName); 117 | writer.writeStringValue("state", state); 118 | writer.writeStringValue("surname", surname); 119 | writer.writeCollectionOfObjectValues("eventDeltas", eventDeltas); 120 | writer.writeAdditionalData(additionalData); 121 | } 122 | 123 | public static TestUser createFromDiscriminatorValue(ParseNode parseNode) { 124 | if (parseNode == null) { 125 | throw new IllegalArgumentException("parseNode cannot be null"); 126 | } 127 | return new TestUser(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /.github/policies/msgraph-sdk-java-core-branch-protection.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT License. 3 | 4 | name: msgraph-sdk-java-core-branch-protection 5 | description: Branch protection policy for the msgraph-sdk-java-core repository 6 | resource: repository 7 | configuration: 8 | branchProtectionRules: 9 | 10 | - branchNamePattern: main 11 | # This branch pattern applies to the following branches as of 20/05/2024 10:31:16: 12 | # main 13 | 14 | # Specifies whether this branch can be deleted. boolean 15 | allowsDeletions: false 16 | # Specifies whether forced pushes are allowed on this branch. boolean 17 | allowsForcePushes: false 18 | # Specifies whether new commits pushed to the matching branches dismiss pull request review approvals. boolean 19 | dismissStaleReviews: true 20 | # Specifies whether admins can overwrite branch protection. boolean 21 | isAdminEnforced: false 22 | # Indicates whether "Require a pull request before merging" is enabled. boolean 23 | requiresPullRequestBeforeMerging: true 24 | # Specifies the number of pull request reviews before merging. int (0-6). Should be null/empty if PRs are not required 25 | requiredApprovingReviewsCount: 1 26 | # Require review from Code Owners. Requires requiredApprovingReviewsCount. boolean 27 | requireCodeOwnersReview: true 28 | # Are commits required to be signed. boolean. TODO: all contributors must have commit signing on local machines. 29 | requiresCommitSignatures: false 30 | # Are conversations required to be resolved before merging? boolean 31 | requiresConversationResolution: true 32 | # Are merge commits prohibited from being pushed to this branch. boolean 33 | requiresLinearHistory: false 34 | # Required status checks to pass before merging. Values can be any string, but if the value does not correspond to any existing status check, the status check will be stuck on pending for status since nothing exists to push an actual status 35 | requiredStatusChecks: 36 | - license/cla 37 | - Build 38 | - lint-api-level 39 | - Analyze (java) 40 | - build 41 | # Require branches to be up to date before merging. Requires requiredStatusChecks. boolean 42 | requiresStrictStatusChecks: true 43 | # Indicates whether there are restrictions on who can push. boolean. Should be set with whoCanPush. 44 | restrictsPushes: false 45 | # Restrict who can dismiss pull request reviews. boolean 46 | restrictsReviewDismissals: false 47 | 48 | - branchNamePattern: support/2.x.x 49 | # This branch pattern applies to the following branches as of 2/14/2024 12:24 50 | # support/2.x.x 51 | 52 | # Specifies whether this branch can be deleted. boolean 53 | allowsDeletions: false 54 | # Specifies whether forced pushes are allowed on this branch. boolean 55 | allowsForcePushes: false 56 | # Specifies whether new commits pushed to the matching branches dismiss pull request review approvals. boolean 57 | dismissStaleReviews: true 58 | # Specifies whether admins can overwrite branch protection. boolean 59 | isAdminEnforced: false 60 | # Indicates whether "Require a pull request before merging" is enabled. boolean 61 | requiresPullRequestBeforeMerging: true 62 | # Specifies the number of pull request reviews before merging. int (0-6). Should be null/empty if PRs are not required 63 | requiredApprovingReviewsCount: 1 64 | # Require review from Code Owners. Requires requiredApprovingReviewsCount. boolean 65 | requireCodeOwnersReview: true 66 | # Are commits required to be signed. boolean. TODO: all contributors must have commit signing on local machines. 67 | requiresCommitSignatures: false 68 | # Are conversations required to be resolved before merging? boolean 69 | requiresConversationResolution: true 70 | # Are merge commits prohibited from being pushed to this branch. boolean 71 | requiresLinearHistory: false 72 | # Required status checks to pass before merging. Values can be any string, but if the value does not correspond to any existing status check, the status check will be stuck on pending for status since nothing exists to push an actual status 73 | requiredStatusChecks: 74 | - license/cla 75 | - Build 76 | - lint-api-level 77 | - Analyze (java) 78 | - build 79 | # Require branches to be up to date before merging. Requires requiredStatusChecks. boolean 80 | requiresStrictStatusChecks: true 81 | # Indicates whether there are restrictions on who can push. boolean. Should be set with whoCanPush. 82 | restrictsPushes: false 83 | # Restrict who can dismiss pull request reviews. boolean 84 | restrictsReviewDismissals: false 85 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/options/GraphClientOption.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.options; 2 | 3 | import java.util.UUID; 4 | 5 | import com.microsoft.graph.core.requests.FeatureTracker; 6 | import com.microsoft.kiota.Compatibility; 7 | import jakarta.annotation.Nonnull; 8 | import jakarta.annotation.Nullable; 9 | 10 | import com.microsoft.graph.core.CoreConstants; 11 | import com.microsoft.kiota.RequestOption; 12 | 13 | /** 14 | * Options to be passed to the telemetry middleware. 15 | */ 16 | public class GraphClientOption implements RequestOption { 17 | 18 | private String clientRequestId; 19 | private String clientLibraryVersion; 20 | private String coreLibraryVersion; 21 | private String graphServiceTargetVersion; 22 | /** 23 | * Default constructor 24 | */ 25 | public GraphClientOption() { 26 | //Default constructor 27 | } 28 | 29 | /** 30 | * Feature Tracker instance 31 | */ 32 | public final FeatureTracker featureTracker = new FeatureTracker(); 33 | /** 34 | * Sets the client request id 35 | * @param clientRequestId the client request id to set, preferably the string representation of a GUID 36 | */ 37 | public void setClientRequestId(@Nonnull final String clientRequestId) { 38 | if(Compatibility.isBlank(clientRequestId)) { 39 | throw new IllegalArgumentException("clientRequestId cannot be null or empty"); 40 | } 41 | this.clientRequestId = clientRequestId; 42 | } 43 | /** 44 | * Gets the client request id 45 | * @return the client request id 46 | */ 47 | @Nonnull 48 | public String getClientRequestId() { 49 | if(clientRequestId == null) { 50 | clientRequestId = UUID.randomUUID().toString(); 51 | } 52 | return clientRequestId; 53 | } 54 | /** 55 | * Sets a string representation of the client library 56 | * @param clientLibraryVersion client library version specified by user. 57 | */ 58 | public void setClientLibraryVersion(@Nonnull final String clientLibraryVersion) { 59 | if(Compatibility.isBlank(clientLibraryVersion)) 60 | { 61 | throw new IllegalArgumentException("clientLibraryVersion cannot be null or empty"); 62 | } 63 | this.clientLibraryVersion = clientLibraryVersion; 64 | } 65 | /** 66 | * Get the client library version as a string 67 | * If null return null; 68 | * @return client library version. 69 | */ 70 | @Nullable 71 | public String getClientLibraryVersion() { 72 | return this.clientLibraryVersion == null ? null : this.clientLibraryVersion; 73 | } 74 | /** 75 | * Set the core library version as a String, in this format 'x.x.x' 76 | * @param coreLibraryVersion core library version specified by user. 77 | */ 78 | public void setCoreLibraryVersion(@Nonnull final String coreLibraryVersion) { 79 | if(Compatibility.isBlank(coreLibraryVersion)) 80 | { 81 | throw new IllegalArgumentException("coreLibraryVersion cannot be null or empty"); 82 | } 83 | this.coreLibraryVersion = coreLibraryVersion; 84 | } 85 | /** 86 | * Get the core library version as a String, in this format 'x.x.x' 87 | * If null return the value in CoreConstants. 88 | * @return core library version. 89 | */ 90 | @Nonnull 91 | public String getCoreLibraryVersion() { 92 | return this.coreLibraryVersion == null ? CoreConstants.Headers.VERSION : this.coreLibraryVersion; 93 | } 94 | /** 95 | * Set the target version of the api endpoint we are targeting (v1 or beta) 96 | * @param graphServiceVersion the version of the Api endpoint we are targeting 97 | */ 98 | public void setGraphServiceTargetVersion(@Nonnull final String graphServiceVersion) { 99 | if(Compatibility.isBlank(graphServiceVersion)) 100 | { 101 | throw new IllegalArgumentException("graphServiceVersion cannot be null or empty"); 102 | } 103 | this.graphServiceTargetVersion = graphServiceVersion; 104 | } 105 | /** 106 | * Get the target version of the api endpoint we are targeting (v1 or beta) 107 | * return 'v1' if not specified. 108 | * @return the version of the Api endpoint we are targeting. 109 | */ 110 | @Nonnull 111 | public String getGraphServiceTargetVersion() { 112 | return this.graphServiceTargetVersion == null ? "v1.0" : this.graphServiceTargetVersion; 113 | } 114 | 115 | @Override 116 | @Nonnull 117 | public Class getType() { 118 | return (Class) GraphClientOption.class; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/BatchRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import com.microsoft.graph.core.CoreConstants; 4 | import com.microsoft.graph.core.content.BatchRequestContent; 5 | import com.microsoft.graph.core.content.BatchRequestContentCollection; 6 | import com.microsoft.graph.core.content.BatchResponseContent; 7 | import com.microsoft.graph.core.content.BatchResponseContentCollection; 8 | import com.microsoft.graph.core.ErrorConstants; 9 | import com.microsoft.kiota.HttpMethod; 10 | import com.microsoft.kiota.NativeResponseHandler; 11 | import com.microsoft.kiota.RequestAdapter; 12 | import com.microsoft.kiota.RequestInformation; 13 | import com.microsoft.kiota.serialization.Parsable; 14 | import com.microsoft.kiota.serialization.ParsableFactory; 15 | import okhttp3.Response; 16 | 17 | import jakarta.annotation.Nonnull; 18 | import jakarta.annotation.Nullable; 19 | 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.Objects; 26 | 27 | /** 28 | * A request builder for creating batch requests. 29 | */ 30 | public class BatchRequestBuilder { 31 | private final RequestAdapter requestAdapter; 32 | /** 33 | * Instantiates a new BatchRequestBuilder. 34 | * @param requestAdapter the adapter to use to build requests. 35 | */ 36 | public BatchRequestBuilder(@Nonnull RequestAdapter requestAdapter) { 37 | this.requestAdapter = Objects.requireNonNull(requestAdapter, ErrorConstants.Messages.NULL_PARAMETER + "requestAdapter"); 38 | } 39 | /** 40 | * Posts a batch request. 41 | * @param requestContent the batch request content. 42 | * @param errorMappings the error mappings to use when parsing the response. 43 | * @return the batch response content. 44 | * @throws IOException if there was an error writing the request content. 45 | */ 46 | @Nonnull 47 | public BatchResponseContent post(@Nonnull BatchRequestContent requestContent, @Nullable Map> errorMappings) throws IOException { 48 | Objects.requireNonNull(requestContent, ErrorConstants.Messages.NULL_PARAMETER + "requestContent"); 49 | RequestInformation requestInfo = toPostRequestInformation(requestContent); 50 | NativeResponseHandler nativeResponseHandler = new NativeResponseHandler(); 51 | requestInfo.setResponseHandler(nativeResponseHandler); 52 | requestAdapter.sendPrimitive(requestInfo, errorMappings == null ? null : new HashMap<>(errorMappings) ,InputStream.class); 53 | return new BatchResponseContent((Response) nativeResponseHandler.getValue(), errorMappings); 54 | } 55 | /** 56 | * Posts a BatchRequestContentCollection. 57 | * @param batchRequestContentCollection the BatchRequestContentCollection to post. 58 | * @param errorMappings the error mappings to use when parsing the response. 59 | * @return the BatchResponseContentCollection. 60 | * @throws IOException if there was an error writing the request content. 61 | */ 62 | @Nonnull 63 | public BatchResponseContentCollection post(@Nonnull BatchRequestContentCollection batchRequestContentCollection, @Nullable Map> errorMappings) throws IOException { 64 | BatchResponseContentCollection collection = new BatchResponseContentCollection(); 65 | List requests = batchRequestContentCollection.getBatchRequestsForExecution(); 66 | for (BatchRequestContent request : requests) { 67 | BatchResponseContent responseContent = post(request, errorMappings); 68 | collection.addBatchResponse(request.getBatchRequestSteps().keySet(), responseContent); 69 | } 70 | return collection; 71 | } 72 | /** 73 | * Creates the request information for a batch request. 74 | * @param requestContent the batch request content. 75 | * @return the request information. 76 | * @throws IOException if there was an error writing the request content. 77 | */ 78 | @Nonnull 79 | public RequestInformation toPostRequestInformation(@Nonnull BatchRequestContent requestContent) throws IOException { 80 | Objects.requireNonNull(requestContent, ErrorConstants.Messages.NULL_PARAMETER + "requestContent"); 81 | RequestInformation requestInfo = new RequestInformation(); 82 | requestInfo.httpMethod = HttpMethod.POST; 83 | requestInfo.urlTemplate = "{+baseurl}/$batch"; 84 | requestInfo.content = requestContent.getBatchRequestContent(); 85 | requestInfo.headers.add("Content-Type", CoreConstants.MimeTypeNames.APPLICATION_JSON); 86 | return requestInfo; 87 | } 88 | /** 89 | * Gets the request adapter. 90 | * @return the request adapter. 91 | */ 92 | @Nonnull 93 | public RequestAdapter getRequestAdapter() { 94 | return requestAdapter; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/testModels/TestResourceData.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.testModels; 2 | 3 | import com.microsoft.kiota.serialization.AdditionalDataHolder; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParseNode; 6 | import com.microsoft.kiota.serialization.SerializationWriter; 7 | import com.microsoft.kiota.store.BackedModel; 8 | import com.microsoft.kiota.store.BackingStore; 9 | import com.microsoft.kiota.store.BackingStoreFactorySingleton; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Objects; 13 | 14 | public class TestResourceData implements AdditionalDataHolder, BackedModel, Parsable { 15 | /** 16 | * Stores model information. 17 | */ 18 | @jakarta.annotation.Nonnull 19 | protected BackingStore backingStore; 20 | /** 21 | * Instantiates a new {@link TestResourceData} and sets the default values. 22 | */ 23 | public TestResourceData() { 24 | this.backingStore = BackingStoreFactorySingleton.instance.createBackingStore(); 25 | this.setAdditionalData(new HashMap<>()); 26 | } 27 | /** 28 | * Creates a new instance of the appropriate class based on discriminator value 29 | * @param parseNode The parse node to use to read the discriminator value and create the object 30 | * @return a {@link TestResourceData} 31 | */ 32 | @jakarta.annotation.Nonnull 33 | public static TestResourceData createFromDiscriminatorValue(@jakarta.annotation.Nonnull final ParseNode parseNode) { 34 | Objects.requireNonNull(parseNode); 35 | return new TestResourceData(); 36 | } 37 | /** 38 | * Gets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. 39 | * @return a {@link Map} 40 | */ 41 | @jakarta.annotation.Nonnull 42 | public Map getAdditionalData() { 43 | Map value = this.backingStore.get("additionalData"); 44 | if(value == null) { 45 | value = new HashMap<>(); 46 | this.setAdditionalData(value); 47 | } 48 | return value; 49 | } 50 | /** 51 | * Gets the backingStore property value. Stores model information. 52 | * @return a {@link BackingStore} 53 | */ 54 | @jakarta.annotation.Nonnull 55 | public BackingStore getBackingStore() { 56 | return this.backingStore; 57 | } 58 | /** 59 | * The deserialization information for the current model 60 | * @return a {@link Map>} 61 | */ 62 | @jakarta.annotation.Nonnull 63 | public Map> getFieldDeserializers() { 64 | final HashMap> deserializerMap = new HashMap>(1); 65 | deserializerMap.put("@odata.type", (n) -> { this.setOdataType(n.getStringValue()); }); 66 | return deserializerMap; 67 | } 68 | /** 69 | * Gets the @odata.type property value. The OdataType property 70 | * @return a {@link String} 71 | */ 72 | @jakarta.annotation.Nullable 73 | public String getOdataType() { 74 | return this.backingStore.get("odataType"); 75 | } 76 | /** 77 | * Serializes information the current object 78 | * @param writer Serialization writer to use to serialize this model 79 | */ 80 | public void serialize(@jakarta.annotation.Nonnull final SerializationWriter writer) { 81 | Objects.requireNonNull(writer); 82 | writer.writeStringValue("@odata.type", this.getOdataType()); 83 | writer.writeAdditionalData(this.getAdditionalData()); 84 | } 85 | /** 86 | * Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. 87 | * @param value Value to set for the AdditionalData property. 88 | */ 89 | public void setAdditionalData(@jakarta.annotation.Nullable final Map value) { 90 | this.backingStore.set("additionalData", value); 91 | } 92 | /** 93 | * Sets the backingStore property value. Stores model information. 94 | * @param value Value to set for the backingStore property. 95 | */ 96 | public void setBackingStore(@jakarta.annotation.Nonnull final BackingStore value) { 97 | Objects.requireNonNull(value); 98 | this.backingStore = value; 99 | } 100 | /** 101 | * Sets the @odata.type property value. The OdataType property 102 | * @param value Value to set for the @odata.type property. 103 | */ 104 | public void setOdataType(@jakarta.annotation.Nullable final String value) { 105 | this.backingStore.set("odataType", value); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/upload/UploadSliceRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.upload; 2 | 3 | import com.microsoft.graph.core.models.UploadResult; 4 | import com.microsoft.kiota.*; 5 | import com.microsoft.kiota.serialization.Parsable; 6 | import com.microsoft.kiota.serialization.ParsableFactory; 7 | import okhttp3.Response; 8 | 9 | import jakarta.annotation.Nonnull; 10 | import java.io.InputStream; 11 | import java.util.Locale; 12 | import java.util.Objects; 13 | 14 | /** 15 | * Request for uploading a slice of a large file. 16 | * @param The type of the object being uploaded. 17 | */ 18 | public class UploadSliceRequestBuilder { 19 | 20 | private final UploadResponseHandler responseHandler; 21 | private final RequestAdapter requestAdapter; 22 | private final String urlTemplate; 23 | private final long rangeBegin; 24 | private final long rangeEnd; 25 | private final long totalSessionLength; 26 | private final long rangeLength; 27 | private final ParsableFactory factory; 28 | 29 | /** 30 | * Request for uploading one slice of a session. 31 | * @param sessionUrl URL to upload the slice. 32 | * @param requestAdapter Request adapted used for uploading the slice. 33 | * @param rangeBegin Beginning of the range for this slice. 34 | * @param rangeEnd End of the range for this slice. 35 | * @param totalSessionLength Total session length. This MUST be consistent. 36 | * @param factory The ParsableFactory defining the instantiation of the object being uploaded. 37 | */ 38 | public UploadSliceRequestBuilder(@Nonnull String sessionUrl, 39 | @Nonnull final RequestAdapter requestAdapter, 40 | long rangeBegin, 41 | long rangeEnd, 42 | long totalSessionLength, 43 | @Nonnull ParsableFactory factory) { 44 | if(Compatibility.isBlank(sessionUrl)) 45 | { 46 | throw new IllegalArgumentException("sessionUrl cannot be null or empty"); 47 | } 48 | this.urlTemplate = sessionUrl; 49 | this.requestAdapter = Objects.requireNonNull(requestAdapter); 50 | this.factory = factory; 51 | this.rangeBegin = rangeBegin; 52 | this.rangeEnd = rangeEnd; 53 | this.rangeLength = (rangeEnd-rangeBegin+1); 54 | this.totalSessionLength = totalSessionLength; 55 | this.responseHandler = new UploadResponseHandler(); 56 | } 57 | /** 58 | * Uploads the slice using PUT. 59 | * @param stream The stream of data to be uploaded. 60 | * @return The model containing the Upload information retrieved from the response. 61 | */ 62 | @Nonnull 63 | public UploadResult put(@Nonnull InputStream stream) { 64 | Objects.requireNonNull(stream); 65 | RequestInformation requestInformation = this.toPutRequestInformation(stream); 66 | NativeResponseHandler nativeResponseHandler = new NativeResponseHandler(); 67 | requestInformation.setResponseHandler(nativeResponseHandler); 68 | requestAdapter.sendPrimitive(requestInformation,null, InputStream.class); 69 | return responseHandler.handleResponse((Response) nativeResponseHandler.getValue(), factory); 70 | } 71 | private RequestInformation toPutRequestInformation(InputStream stream) { 72 | Objects.requireNonNull(stream); 73 | RequestInformation requestInfo = new RequestInformation(); 74 | requestInfo.httpMethod = HttpMethod.PUT; 75 | requestInfo.urlTemplate = this.urlTemplate; 76 | requestInfo.setStreamContent(stream,"application/octet-stream"); 77 | requestInfo.headers.add("Content-Range", String.format(Locale.US, "bytes %d-%d/%d", this.rangeBegin, this.rangeEnd, this.totalSessionLength)); 78 | requestInfo.headers.add("Content-Length", ""+this.rangeLength); 79 | return requestInfo; 80 | } 81 | /** 82 | * Get the range of bytes for this slice. 83 | * @return the range of bytes in this slice. 84 | */ 85 | public long getRangeLength() { 86 | return rangeLength; 87 | } 88 | /** 89 | * Get the starting byte position for this upload slice. 90 | * @return The byte position where this upload slice begins. 91 | */ 92 | public long getRangeBegin() { 93 | return rangeBegin; 94 | } 95 | /** 96 | * Get the ending byte position for this upload slice. 97 | * @return the position where this upload slice ends. 98 | */ 99 | public long getRangeEnd() { 100 | return rangeEnd; 101 | } 102 | /** 103 | * Get the total number of bytes being uploaded in the session. 104 | * @return The total number of bytes in this upload session. 105 | */ 106 | public long getTotalSessionLength() { 107 | return totalSessionLength; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.middleware; 2 | 3 | import java.io.IOException; 4 | import java.lang.reflect.Field; 5 | import java.util.Objects; 6 | 7 | import com.microsoft.graph.core.requests.options.GraphClientOption; 8 | import jakarta.annotation.Nonnull; 9 | 10 | import com.microsoft.graph.core.CoreConstants; 11 | 12 | import okhttp3.Interceptor; 13 | import okhttp3.Request; 14 | import okhttp3.Response; 15 | 16 | /** 17 | * Middleware responsible for adding telemetry information on SDK usage 18 | * Note: the telemetry only collects anonymous information on SDK version and usage. No personal information is collected. 19 | */ 20 | public class GraphTelemetryHandler implements Interceptor{ 21 | 22 | private GraphClientOption mGraphClientOption; 23 | 24 | /** 25 | * Instantiate a GraphTelemetryHandler with default GraphClientOption. 26 | */ 27 | public GraphTelemetryHandler(){ 28 | this(new GraphClientOption()); 29 | } 30 | /** 31 | * Instantiate a GraphTelemetryHandler with specified GraphClientOption 32 | * @param graphClientOption the specified GraphClientOption for the GraphTelemetryHandler. 33 | */ 34 | public GraphTelemetryHandler(@Nonnull final GraphClientOption graphClientOption){ 35 | this.mGraphClientOption = Objects.requireNonNull(graphClientOption); 36 | } 37 | 38 | @Override 39 | @Nonnull 40 | public Response intercept(@Nonnull final Chain chain) throws IOException { 41 | final Request request = chain.request(); 42 | final Request.Builder telemetryAddedBuilder = request.newBuilder(); 43 | 44 | final String clientLibraryUsed = "graph-java" + (mGraphClientOption.getGraphServiceTargetVersion().equals("v1.0") ? "" : "-"+mGraphClientOption.getGraphServiceTargetVersion()); //graph-java | graph-java-beta 45 | final String sdkVersion = (mGraphClientOption.getClientLibraryVersion() == null ? "" : "/"+ mGraphClientOption.getClientLibraryVersion()); //SDK version value 46 | 47 | final String coreVersionHeader = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + mGraphClientOption.getCoreLibraryVersion(); //"graph-java-core/3.0.0" 48 | 49 | final String featureUsage = "(featureUsage=" + mGraphClientOption.featureTracker.getSerializedFeatureUsage(); // (featureUsage= 50 | 51 | final String jreVersion = System.getProperty("java.version"); 52 | final String jreVersionHeader = (CoreConstants.Headers.DEFAULT_VERSION_VALUE.equals(jreVersion) ? "" : ("; runtimeEnvironment=JRE/"+jreVersion)); //runtimeEnvironment=JRE/ 53 | 54 | final String androidVersion = getAndroidAPILevel(); // android/ 55 | final String androidVersionHeader = (CoreConstants.Headers.DEFAULT_VERSION_VALUE.equals(androidVersion) ? "" : ("; " + CoreConstants.Headers.ANDROID_VERSION_PREFIX + "/" + androidVersion)); 56 | 57 | final String sdkTelemetry = clientLibraryUsed + sdkVersion + ", " + coreVersionHeader + " " + featureUsage + jreVersionHeader + androidVersionHeader+")"; 58 | 59 | telemetryAddedBuilder.addHeader(CoreConstants.Headers.SDK_VERSION_HEADER_NAME, sdkTelemetry); 60 | if(request.header(CoreConstants.Headers.CLIENT_REQUEST_ID) == null) { 61 | telemetryAddedBuilder.addHeader(CoreConstants.Headers.CLIENT_REQUEST_ID, mGraphClientOption.getClientRequestId()); 62 | } 63 | 64 | return chain.proceed(telemetryAddedBuilder.build()); 65 | } 66 | 67 | private String androidAPILevel; 68 | private String getAndroidAPILevel() { 69 | if(androidAPILevel == null) { 70 | androidAPILevel = getAndroidAPILevelInternal(); 71 | } 72 | return androidAPILevel; 73 | } 74 | 75 | private String getAndroidAPILevelInternal() { 76 | try { 77 | final Class buildClass = Class.forName("android.os.Build"); 78 | final Class[] subclasses = buildClass.getDeclaredClasses(); 79 | Class versionClass = null; 80 | for(final Class subclass : subclasses) { 81 | if(subclass.getName().endsWith("VERSION")) { 82 | versionClass = subclass; 83 | break; 84 | } 85 | } 86 | if(versionClass == null) 87 | return CoreConstants.Headers.DEFAULT_VERSION_VALUE; 88 | else { 89 | final Field sdkVersionField = versionClass.getField("SDK_INT"); 90 | final Object value = sdkVersionField.get(null); 91 | final String valueStr = String.valueOf(value); 92 | return valueStr == null || valueStr.equals("") ? CoreConstants.Headers.DEFAULT_VERSION_VALUE : valueStr; 93 | } 94 | } catch (IllegalAccessException | ClassNotFoundException | NoSuchFieldException ex) { 95 | // we're not on android and return "0" to align with java version which returns "0" when running on android 96 | return CoreConstants.Headers.DEFAULT_VERSION_VALUE; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/content/BatchResponseContentCollection.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.content; 2 | 3 | import com.microsoft.kiota.ResponseHandler; 4 | import com.microsoft.kiota.serialization.Parsable; 5 | import com.microsoft.kiota.serialization.ParsableFactory; 6 | import okhttp3.Response; 7 | 8 | import jakarta.annotation.Nonnull; 9 | import jakarta.annotation.Nullable; 10 | import java.io.InputStream; 11 | import java.util.*; 12 | 13 | /** 14 | * A collection of BatchResponseContent objects. 15 | */ 16 | public class BatchResponseContentCollection { 17 | 18 | private List batchResponses; 19 | 20 | /** 21 | * Instantiates a new Batch response content collection. 22 | */ 23 | public BatchResponseContentCollection() { 24 | batchResponses = new ArrayList<>(); 25 | } 26 | /** 27 | * Add BatchResponseContent object to the collection. 28 | * @param keys the keys of the requests that were batched together. 29 | * @param content the BatchResponseContent object to add to the collection. 30 | */ 31 | public void addBatchResponse(@Nonnull Collection keys, @Nonnull BatchResponseContent content) { 32 | batchResponses.add(new KeyedBatchResponseContent(new HashSet<>(keys), content)); 33 | } 34 | /** 35 | * Gets the BatchResponseContent object containing the response for the request with the given id. 36 | * @param requestId the id of the request to get the response for. 37 | * @return the BatchResponseContent object containing the response for the request with the given id, null if no response was found. 38 | */ 39 | private BatchResponseContent getBatchResponseContaining(@Nonnull String requestId) { 40 | Objects.requireNonNull(requestId); 41 | for(KeyedBatchResponseContent keyedResponse : batchResponses) { 42 | if(keyedResponse.keys.contains(requestId)) { 43 | return keyedResponse.response; 44 | } 45 | } 46 | return null; 47 | } 48 | /** 49 | * Gets the response for the request with the given id. 50 | * @param requestId the id of the request to get the response for. 51 | * @return the response for the request with the given id, null if no response was found. 52 | */ 53 | @Nullable 54 | public Response getResponseById(@Nonnull String requestId) { 55 | Objects.requireNonNull(requestId); 56 | BatchResponseContent response = getBatchResponseContaining(requestId); 57 | return response == null ? null : response.getResponseById(requestId); 58 | } 59 | /** 60 | * Gets the response for the request with the given id. 61 | * @param requestId the id of the request to get the response for. 62 | * @param handler the handler to use when deserializing the response. 63 | * @return the response for the request with the given id, null if no response was found. 64 | * @param the type of the response. 65 | */ 66 | @Nullable 67 | public T getResponseById(@Nonnull String requestId, @Nonnull ResponseHandler handler) { 68 | Objects.requireNonNull(requestId); 69 | BatchResponseContent response = getBatchResponseContaining(requestId); 70 | return response == null ? null : response.getResponseById(requestId, handler); 71 | } 72 | /** 73 | * Gets the response for the request with the given id. 74 | * @param requestId the id of the request to get the response for. 75 | * @param factory the factory to use when deserializing the response. 76 | * @return the response for the request with the given id, null if no response was found. 77 | * @param the type of the response. 78 | */ 79 | @Nullable 80 | public T getResponseById(@Nonnull String requestId, @Nonnull ParsableFactory factory) { 81 | Objects.requireNonNull(requestId); 82 | BatchResponseContent response = getBatchResponseContaining(requestId); 83 | return response == null ? null : response.getResponseById(requestId, factory); 84 | } 85 | /** 86 | * Gets the response for the request with the given id as a stream. 87 | * @param requestId the id of the request to get the response for. 88 | * @return the response for the request with the given id, null if no response was found. 89 | */ 90 | @Nullable 91 | public InputStream getResponseStreamById(@Nonnull String requestId) { 92 | BatchResponseContent response = getBatchResponseContaining(requestId); 93 | return response == null ? null : response.getResponseStreamById(requestId); 94 | } 95 | /** 96 | * Gets the response codes for all the requests in the batch. 97 | * @return the response codes for all the requests in the batch. 98 | */ 99 | @Nonnull 100 | public Map getResponsesStatusCodes() { 101 | HashMap statusCodes = new HashMap<>(); 102 | for(KeyedBatchResponseContent keyedResponse : batchResponses) { 103 | Map responseStatusCodes = keyedResponse.response.getResponsesStatusCode(); 104 | statusCodes.putAll(responseStatusCodes); 105 | } 106 | return statusCodes; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/upload/UploadResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.upload; 2 | 3 | import com.microsoft.graph.core.ErrorConstants; 4 | import com.microsoft.graph.core.models.UploadResult; 5 | import com.microsoft.graph.core.models.UploadSession; 6 | import com.microsoft.kiota.ApiException; 7 | import com.microsoft.kiota.ApiExceptionBuilder; 8 | import com.microsoft.kiota.http.HeadersCompatibility; 9 | import com.microsoft.kiota.serialization.*; 10 | import okhttp3.Response; 11 | import okhttp3.ResponseBody; 12 | 13 | import jakarta.annotation.Nonnull; 14 | import jakarta.annotation.Nullable; 15 | 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.net.HttpURLConnection; 19 | import java.net.URI; 20 | import java.net.URISyntaxException; 21 | import java.util.List; 22 | import java.util.Objects; 23 | 24 | /** 25 | * The request handler for upload requests. 26 | */ 27 | public class UploadResponseHandler { 28 | 29 | private final ParseNodeFactory parseNodeFactory; 30 | /** 31 | * UploadResponseHandler constructor. 32 | */ 33 | public UploadResponseHandler() { 34 | this(null); 35 | } 36 | /** 37 | * UploadResponseHandler constructor. 38 | * @param parseNodeFactory The ParseNodeFactory to use for response parsing. 39 | */ 40 | public UploadResponseHandler(@Nullable ParseNodeFactory parseNodeFactory) { 41 | this.parseNodeFactory = (parseNodeFactory == null) ? ParseNodeFactoryRegistry.defaultInstance : parseNodeFactory; 42 | } 43 | /** 44 | * Process the raw HTTP response from an upload request. 45 | * @param response The HTTP response returned from the upload request. 46 | * @param factory The ParsableFactory defining the instantiation of the object being uploaded. 47 | * @param The type of the object being uploaded. 48 | * @return An UploadResult model containing the information from the server resulting from the upload request. 49 | */ 50 | @Nonnull 51 | public UploadResult handleResponse(@Nonnull final Response response, @Nonnull final ParsableFactory factory) { 52 | Objects.requireNonNull(response); 53 | Objects.requireNonNull(factory); 54 | try (final ResponseBody body = response.body()) { 55 | UploadResult uploadResult = new UploadResult<>(); 56 | String contentLengthHeader = response.headers().get("content-length"); 57 | // rely on content-type OR content-length headers to determine if response body is empty. 58 | // Response body() may be non-null despite being empty in raw response https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html#body-- 59 | // content-length header is not always present in Graph responses. Content-type is more reliable 60 | if (Objects.isNull(body) 61 | || Objects.isNull(body.contentType()) 62 | || (!Objects.isNull(contentLengthHeader) && Integer.parseInt(contentLengthHeader) == 0) 63 | ) { 64 | if (response.code() == HttpURLConnection.HTTP_CREATED) { 65 | final String location = response.headers().get("location"); 66 | if(!Objects.isNull(location) && !location.isEmpty()) { 67 | uploadResult.location = new URI(location); 68 | return uploadResult; 69 | } 70 | } 71 | throw new ApiException(ErrorConstants.Messages.NO_RESPONSE_FOR_UPLOAD); 72 | } 73 | try(final InputStream in = body.byteStream()){ 74 | if(!response.isSuccessful()) { 75 | throw new ApiExceptionBuilder() 76 | .withMessage(ErrorConstants.Codes.GENERAL_EXCEPTION) 77 | .withResponseStatusCode(response.code()) 78 | .withResponseHeaders(HeadersCompatibility.getResponseHeaders(response.headers())) 79 | .build(); 80 | } 81 | boolean canBeParsed = (!Objects.isNull(contentLengthHeader) && Integer.parseInt(contentLengthHeader) > 0) || !Objects.isNull(body.contentType()); 82 | String contentType = canBeParsed ? body.contentType().toString().split(";")[0] : null; //contentType.toString() returns in format ;, we only want the mediaType. 83 | if (canBeParsed) { 84 | final ParseNode parseNode = parseNodeFactory.getParseNode(contentType, in); 85 | if (response.code() == HttpURLConnection.HTTP_CREATED) { 86 | uploadResult.itemResponse = parseNode.getObjectValue(factory); 87 | } else { 88 | final UploadSession uploadSession = parseNode.getObjectValue(UploadSession::createFromDiscriminatorValue); 89 | final List nextExpectedRanges = uploadSession.getNextExpectedRanges(); 90 | if (!(nextExpectedRanges == null || nextExpectedRanges.isEmpty())) { 91 | uploadResult.uploadSession = uploadSession; 92 | } else { 93 | uploadResult.itemResponse = parseNode.getObjectValue(factory); 94 | } 95 | } 96 | } 97 | return uploadResult; 98 | } 99 | } 100 | catch(IOException | URISyntaxException ex) { 101 | throw new RuntimeException(ex); 102 | } 103 | } 104 | 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/main/java/com/microsoft/graph/core/requests/ResponseBodyHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests; 2 | 3 | import com.microsoft.graph.core.ErrorConstants; 4 | import com.microsoft.kiota.ApiException; 5 | import com.microsoft.kiota.ApiExceptionBuilder; 6 | import com.microsoft.kiota.http.HeadersCompatibility; 7 | import com.microsoft.kiota.serialization.*; 8 | 9 | import okhttp3.Response; 10 | import okhttp3.ResponseBody; 11 | 12 | import jakarta.annotation.Nonnull; 13 | import jakarta.annotation.Nullable; 14 | import java.io.*; 15 | import java.util.HashMap; 16 | 17 | /** 18 | * A response handler for deserializing responses to a ModelType. Particularly for Batch requests. 19 | * @param the ModelType of the response body. 20 | */ 21 | public class ResponseBodyHandler implements com.microsoft.kiota.ResponseHandler { 22 | private final ParseNodeFactory parseNodeFactory; 23 | private final ParsableFactory factory; 24 | /** 25 | * Instantiates a new response handler. 26 | * @param parseNodeFactory the parse node factory to use when deserializing the response. 27 | * @param factory the factory to use when deserializing the response to a ModelType. 28 | */ 29 | public ResponseBodyHandler(@Nullable ParseNodeFactory parseNodeFactory, @Nonnull ParsableFactory factory) { 30 | this.parseNodeFactory = (parseNodeFactory == null) ? ParseNodeFactoryRegistry.defaultInstance : parseNodeFactory; 31 | this.factory = factory; 32 | } 33 | /** 34 | * Instantiates a new response handler. 35 | * @param factory the factory to use when deserializing the response to a ModelType. 36 | */ 37 | public ResponseBodyHandler(@Nonnull ParsableFactory factory) { 38 | this(null, factory); 39 | } 40 | /** 41 | * Handles the response and returns the deserialized response body as a ModelType. 42 | * @param response The native response object. 43 | * @param errorMappings the error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present. 44 | * @return the deserialized response. 45 | * @param The type of the native response object. 46 | * @param The type of the response model object. 47 | */ 48 | @Nullable 49 | @Override 50 | public ModelType handleResponse(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) { 51 | if(response instanceof Response && ((Response) response).body()!=null) { 52 | Response nativeResponse = (Response) response; 53 | ResponseBody body = nativeResponse.body(); 54 | try(final InputStream in = body.byteStream()) { 55 | ParseNode parseNode = this.parseNodeFactory.getParseNode(body.contentType().type() + "/" + body.contentType().subtype(), in); 56 | body.close(); 57 | if(nativeResponse.isSuccessful()) { 58 | final ModelType result = (ModelType) parseNode.getObjectValue(this.factory); //We can be sure this is the correct type since return of this method is based on the type of the factory. 59 | return result; 60 | } else { 61 | handleFailedResponse(nativeResponse, errorMappings, parseNode); 62 | } 63 | } 64 | catch(IOException ex) { 65 | throw new RuntimeException(ex); 66 | } 67 | } else { 68 | throw new IllegalArgumentException("The provided response type is not supported by this response handler."); 69 | } 70 | return null; 71 | } 72 | 73 | private void handleFailedResponse(Response nativeResponse, HashMap> errorMappings, ParseNode parseNode) { 74 | int statusCode = nativeResponse.code(); 75 | String statusCodeString = String.valueOf(statusCode); 76 | if (errorMappings == null || 77 | !errorMappings.containsKey(statusCodeString) && 78 | !(statusCode >= 400 && statusCode <= 499 && errorMappings.containsKey("4XX")) && 79 | !(statusCode >= 500 && statusCode <= 599 && errorMappings.containsKey("5XX"))) { 80 | throw new ApiExceptionBuilder() 81 | .withMessage(ErrorConstants.Codes.GENERAL_EXCEPTION) 82 | .withResponseStatusCode(statusCode) 83 | .withResponseHeaders(HeadersCompatibility.getResponseHeaders(nativeResponse.headers())) 84 | .build(); 85 | } else { 86 | String statusCodePattern = statusCodeString; 87 | if (!errorMappings.containsKey(statusCodePattern)) { 88 | if (statusCode >= 400 && statusCode <= 499 && errorMappings.containsKey("4XX")) { 89 | statusCodePattern = "4XX"; 90 | } else if (statusCode >= 500 && statusCode <= 599 && errorMappings.containsKey("5XX")) { 91 | statusCodePattern = "5XX"; 92 | } 93 | } 94 | Parsable result = parseNode.getObjectValue(errorMappings.get(statusCodePattern)); 95 | if (!(result instanceof Exception)) { 96 | throw new ApiException("The server returned an unexpected status code and the error registered for this code failed to deserialize: " + statusCodeString); 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.graph.core.requests.middleware; 2 | 3 | import com.microsoft.graph.core.CoreConstants; 4 | import com.microsoft.graph.core.requests.GraphClientFactory; 5 | import com.microsoft.graph.core.requests.options.GraphClientOption; 6 | import com.microsoft.kiota.http.middleware.RedirectHandler; 7 | import com.microsoft.kiota.http.middleware.RetryHandler; 8 | 9 | import okhttp3.Interceptor; 10 | import okhttp3.OkHttpClient; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | 14 | import org.junit.jupiter.api.Test; 15 | 16 | import static org.junit.jupiter.api.Assertions.assertNotNull; 17 | import static org.junit.jupiter.api.Assertions.assertTrue; 18 | 19 | import java.io.IOException; 20 | 21 | class GraphTelemetryHandlerTest { 22 | 23 | private static final String defaultSDKVersion = "graph-java"; 24 | 25 | @Test 26 | void telemetryHandlerDefaultTests() throws IOException { 27 | final String expectedCore = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + CoreConstants.Headers.VERSION; 28 | 29 | final OkHttpClient client = GraphClientFactory.create().build(); 30 | final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); 31 | final Response response = client.newCall(request).execute(); 32 | 33 | assertNotNull(response); 34 | assertNotNull(response.request()); 35 | assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); 36 | assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); 37 | assertTrue(!response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains( 38 | CoreConstants.Headers.ANDROID_VERSION_PREFIX)); // Android version is not going to be present on unit tests running on java platform 39 | assertTrue( 40 | response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); 41 | } 42 | 43 | @Test 44 | void arrayInterceptorsTest() throws IOException { 45 | final String expectedCore = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + CoreConstants.Headers.VERSION; 46 | 47 | final Interceptor[] interceptors = {new GraphTelemetryHandler(), new RetryHandler(), 48 | new RedirectHandler()}; 49 | final OkHttpClient client = GraphClientFactory.create(interceptors).build(); 50 | final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); 51 | final Response response = client.newCall(request).execute(); 52 | 53 | assertNotNull(response); 54 | assertNotNull(response.request()); 55 | assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); 56 | assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); 57 | assertTrue( 58 | response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); 59 | } 60 | 61 | @Test 62 | void arrayInterceptorEmptyTest() throws IOException { 63 | final String expectedCore = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + CoreConstants.Headers.VERSION; 64 | 65 | final Interceptor[] interceptors = new Interceptor[]{}; 66 | final OkHttpClient client = GraphClientFactory.create(interceptors).build(); 67 | final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); 68 | final Response response = client.newCall(request).execute(); 69 | 70 | assertNotNull(response); 71 | assertNotNull(response.request()); 72 | assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); 73 | assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCore)); 74 | assertTrue( 75 | response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(defaultSDKVersion)); 76 | } 77 | 78 | @Test 79 | void testClientOptions() throws IOException { 80 | String requestId = "1234567890"; 81 | String coreLibVer = "3.1.1"; 82 | String clientLibVer = "6.1.1"; 83 | String serviceLibVer = "beta"; 84 | 85 | final GraphClientOption graphClientOption = new GraphClientOption(); 86 | graphClientOption.setClientRequestId(requestId); 87 | graphClientOption.setCoreLibraryVersion(coreLibVer); 88 | graphClientOption.setClientLibraryVersion(clientLibVer); 89 | graphClientOption.setGraphServiceTargetVersion(serviceLibVer); 90 | 91 | final String expectedCoreVer = 92 | CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + coreLibVer; 93 | final String expectedClientEndpoint = 94 | CoreConstants.Headers.JAVA_VERSION_PREFIX + "-" + serviceLibVer + "/" + clientLibVer; 95 | 96 | final OkHttpClient client = GraphClientFactory.create(graphClientOption).build(); 97 | final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/users/").build(); 98 | final Response response = client.newCall(request).execute(); 99 | 100 | assertNotNull(response); 101 | assertNotNull(response.request()); 102 | assertNotNull(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME)); 103 | assertTrue(response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedCoreVer)); 104 | assertTrue( 105 | response.request().header(CoreConstants.Headers.SDK_VERSION_HEADER_NAME).contains(expectedClientEndpoint)); 106 | assertTrue(response.request().header(CoreConstants.Headers.CLIENT_REQUEST_ID).contains(requestId)); 107 | } 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsoft Graph Core SDK for Java 2 | 3 | [![Download](https://img.shields.io/maven-central/v/com.microsoft.graph/microsoft-graph-core.svg)](https://search.maven.org/artifact/com.microsoft.graph/microsoft-graph-core) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=microsoftgraph_msgraph-sdk-java-core&metric=coverage)](https://sonarcloud.io/dashboard?id=microsoftgraph_msgraph-sdk-java-core) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=microsoftgraph_msgraph-sdk-java-core&metric=alert_status)](https://sonarcloud.io/dashboard?id=microsoftgraph_msgraph-sdk-java-core) 4 | 5 | Get started with the Microsoft Graph Core SDK for Java by integrating the [Microsoft Graph API](https://developer.microsoft.com/en-us/graph/get-started/java) into your Java and Android application! You can also have a look at the [Javadoc](https://docs.microsoft.com/en-us/java/api/com.microsoft.graph.httpcore?view=graph-core-java) 6 | 7 | ## Samples and usage guide 8 | 9 | - [Middleware usage](https://github.com/microsoftgraph/msgraph-sdk-design/) 10 | - [Batching](https://docs.microsoft.com/en-us/graph/sdks/batch-requests?tabs=java) 11 | 12 | ## 1. Installation 13 | 14 | ### 1.1 Install via Gradle 15 | 16 | Add the repository and a compile dependency for `microsoft-graph-core` to your project's `build.gradle`: 17 | 18 | ```groovy 19 | repositories { 20 | mavenCentral() 21 | } 22 | 23 | dependencies { 24 | // Include the sdk as a dependency 25 | // x-release-please-start-version 26 | implementation 'com.microsoft.graph:microsoft-graph-core:3.6.5' 27 | // x-release-please-end 28 | // This dependency is only needed if you are using the TokenCredentialAuthProvider 29 | implementation 'com.azure:azure-identity:1.11.0' 30 | } 31 | ``` 32 | 33 | ### 1.2 Install via Maven 34 | 35 | Add the dependency in `dependencies` in pom.xml 36 | 37 | ```xml 38 | 39 | 40 | com.microsoft.graph 41 | microsoft-graph-core 42 | 43 | 3.6.5 44 | 45 | 46 | com.azure 47 | azure-identity 48 | 1.11.0 49 | 50 | ``` 51 | 52 | ### 1.3 Enable ProGuard (Android) 53 | 54 | The nature of the Graph API is such that the SDK needs quite a large set of classes to describe its functionality. You need to ensure that [ProGuard](https://developer.android.com/studio/build/shrink-code.html) is enabled on your project. Otherwise, you will incur long build times for functionality that is not necessarily relevant to your particular application. If you are still hitting the 64K method limit, you can also enable [multidexing](https://developer.android.com/studio/build/multidex.html). 55 | 56 | ## 2. Getting started 57 | 58 | ### 2.1 Register your application 59 | 60 | Register your application by following the steps at [Register your app with the Microsoft Identity Platform](https://docs.microsoft.com/graph/auth-register-app-v2). 61 | 62 | ### 2.2 Create an AuthenticationProvider object 63 | 64 | [Initialize an `AuthenticationProvider`](https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?view=graph-rest-1.0&tabs=java) based on your preferred authentication flow 65 | 66 | ### 2.3 Get a OkHttpClient object 67 | 68 | You must get an **OkHttpClient** object to make requests against the service. 69 | 70 | Using the `GraphClientFactory`, you can initialize an `OkHttpClient` pre-configured for use with Microsoft Graph 71 | 72 | ```java 73 | OkHttpClient client = GraphClientFactory.create(authenticationProvider).build(); 74 | ``` 75 | 76 | ## 3. Make requests against the service 77 | 78 | After you have an authenticated `OkHttpClient`, you can begin making calls against the service. The requests against the service look like our [REST API](https://developer.microsoft.com/en-us/graph/docs/concepts/overview). 79 | 80 | ### 3.1 Get the user's details 81 | 82 | To retrieve the user's details 83 | 84 | ```java 85 | Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build(); 86 | 87 | client.newCall(request).enqueue(new Callback() { 88 | @Override 89 | public void onResponse(Call call, Response response) throws IOException { 90 | String responseBody = response.body().string(); 91 | // Your processing with the response body 92 | } 93 | 94 | @Override 95 | public void onFailure(Call call, IOException e) { 96 | e.printStackTrace(); 97 | } 98 | }); 99 | ``` 100 | 101 | ### 3.2 Get the user's drive 102 | 103 | To retrieve the user's drive: 104 | 105 | ```java 106 | Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/drive").build(); 107 | 108 | client.newCall(request).enqueue(new Callback() { 109 | @Override 110 | public void onResponse(Call call, Response response) throws IOException { 111 | String responseBody = response.body().string(); 112 | // Your processing with the response body 113 | } 114 | 115 | @Override 116 | public void onFailure(Call call, IOException e) { 117 | e.printStackTrace(); 118 | } 119 | }); 120 | ``` 121 | 122 | ## 4. Issues 123 | 124 | For known issues, see [issues](https://github.com/MicrosoftGraph/msgraph-sdk-java-core/issues). 125 | 126 | ## 5. Contributions 127 | 128 | The Microsoft Graph SDK is open for contribution. To contribute to this project, see the [Contributing](https://github.com/microsoftgraph/msgraph-sdk-java-core/blob/main/CONTRIBUTING.md) guide. 129 | 130 | ## 6. Supported Java versions 131 | 132 | The Microsoft Graph SDK for Java library is supported at runtime for Java 8 and [Android API revision 26](http://source.android.com/source/build-numbers.html) or greater. 133 | 134 | ## 7. License 135 | 136 | Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the [MIT license](LICENSE). 137 | 138 | ## 8. Third-party notices 139 | 140 | [Third-party notices](THIRD%20PARTY%20NOTICES) 141 | --------------------------------------------------------------------------------