Skip to content

Commit

Permalink
Add default value provider and annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
devjeonghwan committed Oct 13, 2023
1 parent 8f0eeb9 commit 9c6f15b
Show file tree
Hide file tree
Showing 11 changed files with 441 additions and 3 deletions.
12 changes: 11 additions & 1 deletion src/main/java/com/realtimetech/opack/Opacker.java
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,21 @@ private void executeDeserializeStack(int endOfStack) throws DeserializeException
} else if (opackValue instanceof OpackObject) {
OpackObject<Object, Object> opackObject = (OpackObject<Object, Object>) opackValue;
for (BakedType.Property property : bakedType.getFields()) {
String propertyName = property.getName();

try {
Object element = opackObject.get(property.getName());
Object element;
Class<?> fieldType = property.getType();
Class<?> actualFieldType = property.getField().getType();

if (opackObject.containsKey(propertyName)) {
element = opackObject.get(propertyName);
} else if (property.getDefaultValueProvider() != null) {
element = property.getDefaultValueProvider().provide(this, object, property);
} else {
throw new DeserializeException("Missing " + property.getName() + " property value of for " + bakedType.getType().getSimpleName() + " in given opack value.");
}

Object propertyValue = null;

if (element != null) {
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/com/realtimetech/opack/annotation/DefaultValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 REALTIMETECH All Rights Reserved
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.realtimetech.opack.annotation;

import com.realtimetech.opack.provider.DefaultValueProvider;
import org.jetbrains.annotations.NotNull;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Fields annotated with @DefaultValue will not be serialized and deserialized
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.FIELD,
})
public @interface DefaultValue {
/**
* Return the default value provider for field
*
* @return the default value provider class
*/
@NotNull Class<? extends DefaultValueProvider> provider();
}
9 changes: 8 additions & 1 deletion src/main/java/com/realtimetech/opack/bake/BakedType.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package com.realtimetech.opack.bake;

import com.realtimetech.opack.provider.DefaultValueProvider;
import com.realtimetech.opack.transformer.Transformer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -36,14 +37,16 @@ public final static class Property {
private final boolean withType;

private final @Nullable Transformer transformer;
private final @Nullable DefaultValueProvider defaultValueProvider;

public Property(@NotNull Field field, @Nullable String name, @Nullable Class<?> type, boolean withType, @Nullable Transformer transformer) {
public Property(@NotNull Field field, @Nullable String name, @Nullable Class<?> type, boolean withType, @Nullable Transformer transformer, @Nullable DefaultValueProvider defaultValueProvider) {
this.field = field;
this.name = name == null ? this.field.getName() : name;
this.type = type == null ? this.field.getType() : type;
this.withType = withType;

this.transformer = transformer;
this.defaultValueProvider = defaultValueProvider;
}

public @NotNull Field getField() {
Expand All @@ -66,6 +69,10 @@ public boolean isWithType() {
return transformer;
}

public @Nullable DefaultValueProvider getDefaultValueProvider() {
return defaultValueProvider;
}

/**
* Sets the field of the object to a specified value
*
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/com/realtimetech/opack/bake/TypeBaker.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.realtimetech.opack.Opacker;
import com.realtimetech.opack.annotation.*;
import com.realtimetech.opack.exception.BakeException;
import com.realtimetech.opack.provider.DefaultValueProvider;
import com.realtimetech.opack.provider.DefaultValueProviderFactory;
import com.realtimetech.opack.transformer.Transformer;
import com.realtimetech.opack.transformer.TransformerFactory;
import com.realtimetech.opack.util.ReflectionUtil;
Expand Down Expand Up @@ -65,6 +67,7 @@ public boolean isInheritable() {
private final @NotNull Opacker opacker;

private final @NotNull TransformerFactory transformerFactory;
private final @NotNull DefaultValueProviderFactory defaultValueProviderFactory;

private final @NotNull HashMap<@NotNull Class<?>, @NotNull BakedType> backedTypeMap;
private final @NotNull HashMap<@NotNull Class<?>, @NotNull List<@NotNull PredefinedTransformer>> predefinedTransformerMap;
Expand All @@ -78,6 +81,7 @@ public TypeBaker(@NotNull Opacker opacker) {
this.opacker = opacker;

this.transformerFactory = new TransformerFactory(opacker);
this.defaultValueProviderFactory = new DefaultValueProviderFactory(opacker);

this.backedTypeMap = new HashMap<>();
this.predefinedTransformerMap = new HashMap<>();
Expand Down Expand Up @@ -318,11 +322,25 @@ private void addTransformer(@NotNull List<@NotNull Transformer> transformers, @N
}

Transformer[] fieldTransformers = this.getTransformer(field);
DefaultValueProvider defaultValueProvider = null;

Class<?> type = this.getAnnotatedType(field);
String name = this.getAnnotatedName(field);

boolean withType = field.isAnnotationPresent(WithType.class);

properties.add(new BakedType.Property(field, name, type, withType, fieldTransformers.length > 0 ? fieldTransformers[0] : null));
if (field.isAnnotationPresent(DefaultValue.class)) {
DefaultValue defaultValue = field.getAnnotation(DefaultValue.class);
Class<DefaultValueProvider> defaultValueProviderType = (Class<DefaultValueProvider>) defaultValue.provider();

try {
defaultValueProvider = this.defaultValueProviderFactory.get(defaultValueProviderType);
} catch (InstantiationException e) {
throw new BakeException(e);
}
}

properties.add(new BakedType.Property(field, name, type, withType, fieldTransformers.length > 0 ? fieldTransformers[0] : null, defaultValueProvider));
}

transformers = this.getTransformer(bakeType);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 REALTIMETECH All Rights Reserved
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.realtimetech.opack.provider;

import com.realtimetech.opack.Opacker;
import com.realtimetech.opack.bake.BakedType;
import com.realtimetech.opack.exception.DeserializeException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface DefaultValueProvider {
/**
* Deserialize opack value
*
* @param opacker the opacker
* @param object the property owner
* @param property the property to provide default value
* @return the default value
*/
@Nullable Object provide(@NotNull Opacker opacker, @NotNull Object object, @NotNull BakedType.Property property);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 REALTIMETECH All Rights Reserved
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.realtimetech.opack.provider;

import com.realtimetech.opack.Opacker;
import com.realtimetech.opack.util.ReflectionUtil;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;

public class DefaultValueProviderFactory {
private final @NotNull Opacker opacker;

private final @NotNull HashMap<@NotNull Class<? extends DefaultValueProvider>, @NotNull DefaultValueProvider> defaultValueProviderMap;

/**
* Constructs a TransformerFactory with the opacker
*
* @param opacker the opacker
*/
public DefaultValueProviderFactory(@NotNull Opacker opacker) {
this.opacker = opacker;

this.defaultValueProviderMap = new HashMap<>();
}

/**
* Returns default value provider instance
*
* @param defaultValueProviderType the default value provider class
* @return the default value provider instance
* @throws InstantiationException if the default value provider class object cannot be instantiated; if the default value provider is not in the default value provider class
*/
public <P extends DefaultValueProvider> @NotNull P get(@NotNull Class<P> defaultValueProviderType) throws InstantiationException {
if (!this.defaultValueProviderMap.containsKey(defaultValueProviderType)) {
synchronized (this.defaultValueProviderMap) {
if (!this.defaultValueProviderMap.containsKey(defaultValueProviderType)) {
P instance = null;

try {
// Create instance using DefaultValueProvider(Opacker) constructor
try {
instance = ReflectionUtil.createInstance(defaultValueProviderType, this.opacker);
} catch (IllegalArgumentException exception) {
// Ok, let's find no parameter constructor
}

// Create instance using DefaultValueProvider() constructor
try {
if (instance == null) {
instance = ReflectionUtil.createInstance(defaultValueProviderType);
}
} catch (IllegalArgumentException exception) {
// Ok, let's throw exception
}
} catch (InvocationTargetException | IllegalAccessException exception) {
InstantiationException instantiationException = new InstantiationException(defaultValueProviderType.getSimpleName() + " default value provider can't instantiation.");
instantiationException.initCause(exception);

throw instantiationException;
}

if (instance == null) {
throw new InstantiationException(defaultValueProviderType.getSimpleName() + " default value provider must be implemented constructor(Opacker) or constructor().");
}

this.defaultValueProviderMap.put(defaultValueProviderType, instance);
}
}
}

return defaultValueProviderType.cast(this.defaultValueProviderMap.get(defaultValueProviderType));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 REALTIMETECH All Rights Reserved
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.realtimetech.opack.provider.impl;

import com.realtimetech.opack.Opacker;
import com.realtimetech.opack.bake.BakedType;
import com.realtimetech.opack.provider.DefaultValueProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class BooleanFalseProvider implements DefaultValueProvider {
/**
* Deserialize opack value
*
* @param opacker the opacker
* @param object the property owner
* @param property the property to provide default value
* @return the default value
*/
@Override
public @Nullable Object provide(@NotNull Opacker opacker, @NotNull Object object, BakedType.@NotNull Property property) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 REALTIMETECH All Rights Reserved
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.realtimetech.opack.provider.impl;

import com.realtimetech.opack.Opacker;
import com.realtimetech.opack.bake.BakedType;
import com.realtimetech.opack.provider.DefaultValueProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class BooleanTrueProvider implements DefaultValueProvider {
/**
* Deserialize opack value
*
* @param opacker the opacker
* @param object the property owner
* @param property the property to provide default value
* @return the default value
*/
@Override
public @Nullable Object provide(@NotNull Opacker opacker, @NotNull Object object, BakedType.@NotNull Property property) {
return true;
}
}
Loading

0 comments on commit 9c6f15b

Please sign in to comment.