001/* 002 * VM-Operator 003 * Copyright (C) 2024 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.vmoperator.common; 020 021import com.google.gson.Gson; 022import com.google.gson.InstanceCreator; 023import com.google.gson.JsonObject; 024import com.google.gson.TypeAdapter; 025import com.google.gson.TypeAdapterFactory; 026import com.google.gson.reflect.TypeToken; 027import com.google.gson.stream.JsonReader; 028import com.google.gson.stream.JsonWriter; 029import io.kubernetes.client.openapi.ApiClient; 030import java.io.IOException; 031import java.lang.reflect.InvocationTargetException; 032import java.lang.reflect.Type; 033 034/** 035 * A factory for creating objects. 036 * 037 * @param <O> the generic type 038 * @param <L> the generic type 039 */ 040public class DynamicTypeAdapterFactory<O extends K8sDynamicModel, 041 L extends K8sDynamicModelsBase<O>> implements TypeAdapterFactory { 042 043 private final Class<O> objectClass; 044 private final Class<L> objectListClass; 045 046 /** 047 * Make sure that this adapter is registered. 048 * 049 * @param client the client 050 */ 051 public void register(ApiClient client) { 052 if (!ModelCreator.class 053 .equals(client.getJSON().getGson().getAdapter(objectClass) 054 .getClass()) 055 || !ModelsCreator.class.equals(client.getJSON().getGson() 056 .getAdapter(objectListClass).getClass())) { 057 Gson gson = client.getJSON().getGson(); 058 client.getJSON().setGson(gson.newBuilder() 059 .registerTypeAdapterFactory(this).create()); 060 } 061 } 062 063 /** 064 * Instantiates a new generic type adapter factory. 065 * 066 * @param objectClass the object class 067 * @param objectListClass the object list class 068 */ 069 public DynamicTypeAdapterFactory(Class<O> objectClass, 070 Class<L> objectListClass) { 071 this.objectClass = objectClass; 072 this.objectListClass = objectListClass; 073 } 074 075 /** 076 * Creates a type adapter for the given type. 077 * 078 * @param <T> the generic type 079 * @param gson the gson 080 * @param typeToken the type token 081 * @return the type adapter or null if the type is not handles by 082 * this factory 083 */ 084 @SuppressWarnings("unchecked") 085 @Override 086 public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { 087 if (TypeToken.get(objectClass).equals(typeToken)) { 088 return (TypeAdapter<T>) new ModelCreator(gson); 089 } 090 if (TypeToken.get(objectListClass).equals(typeToken)) { 091 return (TypeAdapter<T>) new ModelsCreator(gson); 092 } 093 return null; 094 } 095 096 /** 097 * The Class ModelCreator. 098 */ 099 private class ModelCreator extends TypeAdapter<O> 100 implements InstanceCreator<O> { 101 private final Gson delegate; 102 103 /** 104 * Instantiates a new object state creator. 105 * 106 * @param delegate the delegate 107 */ 108 public ModelCreator(Gson delegate) { 109 this.delegate = delegate; 110 } 111 112 @Override 113 public O createInstance(Type type) { 114 try { 115 return objectClass.getConstructor(Gson.class, JsonObject.class) 116 .newInstance(delegate, null); 117 } catch (InstantiationException | IllegalAccessException 118 | IllegalArgumentException | InvocationTargetException 119 | NoSuchMethodException | SecurityException e) { 120 return null; 121 } 122 } 123 124 @Override 125 public void write(JsonWriter jsonWriter, O state) 126 throws IOException { 127 jsonWriter.jsonValue(delegate.toJson(state.data())); 128 } 129 130 @Override 131 public O read(JsonReader jsonReader) 132 throws IOException { 133 try { 134 return objectClass.getConstructor(Gson.class, JsonObject.class) 135 .newInstance(delegate, 136 delegate.fromJson(jsonReader, JsonObject.class)); 137 } catch (InstantiationException | IllegalAccessException 138 | IllegalArgumentException | InvocationTargetException 139 | NoSuchMethodException | SecurityException e) { 140 return null; 141 } 142 } 143 } 144 145 /** 146 * The Class ModelsCreator. 147 */ 148 private class ModelsCreator extends TypeAdapter<L> 149 implements InstanceCreator<L> { 150 151 private final Gson delegate; 152 153 /** 154 * Instantiates a new object states creator. 155 * 156 * @param delegate the delegate 157 */ 158 public ModelsCreator(Gson delegate) { 159 this.delegate = delegate; 160 } 161 162 @Override 163 public L createInstance(Type type) { 164 try { 165 return objectListClass 166 .getConstructor(Gson.class, JsonObject.class) 167 .newInstance(delegate, null); 168 } catch (InstantiationException | IllegalAccessException 169 | IllegalArgumentException | InvocationTargetException 170 | NoSuchMethodException | SecurityException e) { 171 return null; 172 } 173 } 174 175 @Override 176 public void write(JsonWriter jsonWriter, L states) 177 throws IOException { 178 jsonWriter.jsonValue(delegate.toJson(states.data())); 179 } 180 181 @Override 182 public L read(JsonReader jsonReader) 183 throws IOException { 184 try { 185 return objectListClass 186 .getConstructor(Gson.class, JsonObject.class) 187 .newInstance(delegate, 188 delegate.fromJson(jsonReader, JsonObject.class)); 189 } catch (InstantiationException | IllegalAccessException 190 | IllegalArgumentException | InvocationTargetException 191 | NoSuchMethodException | SecurityException e) { 192 return null; 193 } 194 } 195 } 196 197}