Title: How can I migrate JCenter artifact to the Sonatype Maven repository?
Tags: maven;migration;sonatype;jcenter
Question: The JCenter Maven repository will be down in some month.
https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/?utm_source=mkto&amp;utm_medium=email&amp;utm_campaign=bintray-sunset&amp;utm_content=global-02-2021
How can I migrate all artifact to Sonatype before it will be deleted.
Comment: https://central.sonatype.org/pages/requirements.html

Here is the accepted answer: I have solve this with multiple steps:
First I have written a Java program to download all the artifacts from my JCenter account.
Then I have write a Gradle script with the Maven plugin. This script use archiveBaseName, version and the directory of the artifacts as parameters. The script and maven plugin add all the missing things like the PGP signature.
Then I write a Java program that iterate over the downloaded artifacts (or a part of it) and call the Gradle script with the parameters archiveBaseName, version and the directory with the artifacts in a loop.
On the Sonatype GUI I deploy the uploaded files. Multiple staffordmadison@example.com.
The follow code snippet which I have used will not work out of the box because it used internal private API. But it can help as start point. Of course you need an sonatype account and a gpg ring file. The secret properties are saved in the gradle.properties. You need also to customize the group name that the company used in all 3 files.
Downloader
package tool;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import com.inet.lib.util.IOFunctions;
public class DownloadJCenter {
// this path will be cut on save
private static String basePath;
private static File   root;
public static void main( String[] args ) throws IOException {
basePath = &quot;/&quot;;
URL startURL = new URL( &quot;https://jcenter.bintray.com/com/company/&quot; );
root = new File( &quot;jcenter&quot; );
load( startURL );
/**
* Load the URL iterative
*
* @param parent the URL to load
* @throws IOException if any error occur
*/
static void load( @Nonnull URL parent ) throws IOException {
System.err.println( parent );
InputStream input = IOFunctions.openStreamSupportingRedirect( parent, 5000 );
String content = IOFunctions.readString( input, StandardCharsets.UTF_8 );
List<URL&gt; urls = extractUrls( parent, content );
for( URL url : urls ) {
String path = url.getPath();
if( path.endsWith( &quot;/&quot; ) ) {
load( url );
} else {
input = IOFunctions.openStreamSupportingRedirect( url, 5000 );
byte[] bytes = IOFunctions.readBytes( input );
File file = new File( root, path.substring( basePath.length() ) );
file.getParentFile().mkdirs();
try (FileOutputStream fos = new FileOutputStream( file )) {
fos.write( bytes );
}
}
}
/**
* Extract the URLs from the content of page
*
* @param parent the parent URL for relative URLs
* @param content the page content
* @return list of found URLs
* @throws IOException if any error occur
*/
@Nonnull
static List<URL&gt; extractUrls( URL parent, @Nonnull String content ) throws IOException {
ArrayList<URL&gt; result = new ArrayList<&gt;();
int idx = 0;
while( true ) {
int idx1 = content.indexOf( &quot;href=\&quot;&quot;, idx );
if( idx1 < 0 ) {
break;
}
idx1 += 6;
int idx2 = content.indexOf( &quot;\&quot;&quot;, idx1 );
String urlStr = content.substring( idx1, idx2 );
if( !urlStr.startsWith( &quot;..&quot; ) ) {
result.add( new URL( parent, urlStr ) );
}
idx = idx2;
}
return result;
Gradle Launcher
package tool;
import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.util.ArrayList;
import java.util.HashMap;
import com.inet.error.ErrorCode;
import com.inet.lib.util.IOFunctions;
import com.inet.shared.utils.Version;
* Deploy to the Sonatype server.
public class DeploySonatype {
private static final String gradle = &quot;C:/Users/...../gradle-6.7.1/bin/gradle.bat&quot;;
public static void main( String[] args ) throws IOException {
File root = new File( &quot;jcenter/com/company&quot; );
for( File file : root.listFiles() ) {
if( file.isDirectory() ) {
String archivesBaseName = file.getName();
deployLibrary( archivesBaseName, file );
}
}
static void deployLibrary( String archivesBaseName, File libraryDir ) throws IOException {
HashMap<Version,File&gt; versionDirs = new HashMap<&gt;();
for( File file : libraryDir.listFiles() ) {
if( file.isDirectory() ) {
versionDirs.put( new Version( file.getName()), file );
}
}
ArrayList<Version&gt; versions = new ArrayList( versionDirs.keySet() );
versions.sort( null );// old versions first
for( Version version : versions ) {
File dir = versionDirs.get( version );
deployVersion( archivesBaseName, version, dir );
}
static void deployVersion( String archivesBaseName, Version version, File dir ) throws IOException {
System.err.println( archivesBaseName + &quot; &quot; + version + &quot; &quot; + dir );
File script = IOFunctions.getFile( DeploySonatype.class.getResource( &quot;deploy.gradle&quot; ) );
IOFunctions.deleteDir( new File( script.getParent(), &quot;build&quot; ) ); // clean from previous run
ArrayList<String&gt; command = new ArrayList<&gt;();
command.add( gradle );
command.add( &quot;-b&quot; );
command.add( &quot;\&quot;&quot; + script.getPath() + &quot;\&quot;&quot; );
command.add( &quot;--stacktrace&quot; );
command.add( &quot;-ParchivesBaseName=&quot; + archivesBaseName );
command.add( &quot;-Pversion=&quot; + version );
command.add( &quot;-PartifactDir=&quot; + dir.getAbsolutePath() );
command.add( &quot;uploadArchives&quot; );
System.err.println( command );
ProcessBuilder processBuilder = new ProcessBuilder( command );
processBuilder.redirectOutput( Redirect.INHERIT );
processBuilder.redirectError( Redirect.INHERIT );
processBuilder.environment().put( &quot;JAVA_HOME&quot;, System.getProperty( &quot;java.home&quot; ) );
Process start = processBuilder.start();
try {
int exitValue = start.waitFor();
if( exitValue != 0 ) {
throw new IOException( &quot;Exit Value: &quot; + exitValue );
}
} catch( InterruptedException ex ) {
ErrorCode.throwAny( ex );
}
deploy.gradle
/****************************************
* Deploy to Maven
****************************************/
apply plugin: 'maven'
apply plugin: 'signing'
group = 'com.company'
println archivesBaseName + &quot;/&quot; + version + &quot;  -&gt; &quot; + artifactDir // come from Java as parameter
task copyArtifact(type: Copy) {
from file( artifactDir )
into file(&quot;$buildDir/artifacts&quot; )
task setupArchives {
dependsOn copyArtifact
doLast {
artifacts {
fileTree( dir: file( &quot;$buildDir/artifacts&quot; ) ).each {
archives file: it
println &quot;\t&quot; + it
}
}
signing {
if (project.hasProperty(&quot;signing.keyId&quot;) ){
sign configurations.archives
}
}
uploadArchives {
dependsOn setupArchives
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -&gt;
signing {
fileTree( dir: file( &quot;$buildDir/artifacts&quot; ) ).each {
sign it
println &quot;sign: &quot; + it
}
}
}
if (project.hasProperty(&quot;ossrhUsername&quot;) ){
repository(url: &quot;https://oss.sonatype.org/service/local/staging/deploy/maven2/&quot;) {
authentication(userName: project[&quot;ossrhUsername&quot;], password: project[&quot;ossrhPassword&quot;])
}
}
}
Comment for this answer: If you bundled that up and put it up as a project on github, or somewhere for people to snag and use, you'd probably get a lot of downloads. Lots of people are going to be in the same boat, looking to migrate artifacts published to JCenter and sync to Maven Central.
Comment for this answer: @MadsHansen I have add the code that I have used. I hope this help you. If you like you can make a Github project with it.


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 1, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2021:00:02/15/21', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<maven><migration><sonatype><jcenter>', 'Title': 'How can I migrate JCenter artifact to the Sonatype Maven repository?', 'ViewCount': 306, 'id': 66214287, 'user_AboutMe': 'nothing', 'user_AccountId': 7295.0, 'user_DisplayName': 'Horcrux7', 'user_Reputation': 23139.0, 'user_Views': 1317.0, 'user_id': 12631.0}}